Initial import

From AU_LINUX_ANDROID_LA.UM.5.7.R1.07.00.00.253.042
being made of the following commits:

57d61bb Promotion of data.lnx.2.0-00072.
8756392 IPACM: change DL routing rule to be non-hashable
6172f4f IPACM: fix the logic in WLAN AP-AP use case
d73f0e7 Promotion of data.lnx.2.0-00069.
cb202c9 IPACM: fix compilation error on IPAv2
98f1764 Promotion of data.lnx.2.0-00067.
ff6a1f9 Merge "IPACM: add support for new QMI message"
033aef1 IPACM: delete client header when interface goes down
3e7c692 Promotion of data.lnx.2.0-00062.
96620a9 Promotion of data.lnx.2.0-00061.
5f55d12 IPACM: Fix the logic of inter-interface communication
203ebcf Promotion of data.lnx.2.0-00058.
06e7c06 IPACM: add support for new QMI message
89365a0 Merge "IPACM: not clean the mac entry in neighbor module"
21f7f88 IPACM: not clean the mac entry in neighbor module
e4aebe9 ipacm: Fix race condition between nat delete and update timestamp
d3eecde Promotion of data.lnx.2.0-00053.
7b7d16a Merge "ipacm: Enable IPACM for msm8940"
4d0e9fd Promotion of data.lnx.2.0-00052.
476d30b IPACM: add STA offload support on Android platform
488bbc8 ipacm: Enable IPACM for msm8940
cad3451 IPACM: adjust ip type maintenance logic
8138e1d Merge "IPACM: ignore early IPv6 default route event"
214a286 Merge "IPACM: fix the ip type issue"
3af7488 Promotion of data.lnx.2.0-00050.
8540322 Merge "IPACM: add wlan2 and wlan3 in xml file"
001391e Merge "IPACM: ignore invalid new neighbor message"
1468b49 IPACM: ignore early IPv6 default route event
f4e88b3 IPACM: fix KW issues
c8c6755 IPACM: fix the ip type issue
a614891 Merge "IPACM: Cache non nat ifaces only for backhaul mode"
2b6c742 Merge "IPACM: fix KW issue"
fe1f3ba Merge "IPACM: change WLAN category back to UNKNOWN_IF"
8242bfa Merge "ipacm: changes related to IP Passhthrough"
d485dd9 Merge "IPACM: call ioctl IPA_IOC_PUT_RT_TBL"
d9b2eaa IPACM: Cache non nat ifaces only for backhaul mode
a9d53ce IPACM: Add dummy nat rules only for modem backhaul
18ed683 ipacm: changes related to IP Passhthrough
df178de IPACM: change WLAN category back to UNKNOWN_IF
8c5a6d9 IPACM: fix KW issue
f35038b IPACM: add wlan2 and wlan3 in xml file
7ca34e7 IPACM: ignore invalid new neighbor message
615dfb0 IPACM: fix KW issue
b720974 ipacm: Fix NULL pointer and boundary check
6fb842a IPACM: Fix the dangling reference
d930392 IPACM: call ioctl IPA_IOC_PUT_RT_TBL
edfee47 ipacm: Buffer overflow
34b018d IPACM: fix hashable filtering rule issue
bf2f775 Merge "IPACM: increase modem UL filtering rule cache" into data.lnx.2.0-dev
0262ca1 IPACM: increase modem UL filtering rule cache
ba6fe11 IPACM: Add support for cobalt target
ce89939 IPACM: Add Ethernet bridging central controller
00cdfd1 IPACM: add structure of two message queues
c7ca219 IPACM: disable firewall monitor for Android
2f11160 IPACM: fix KW issues
6ae5e61 IPACM: refactoring filtering on LAN/WLAN interfaces
b81a389 IPACM: Fix hashable fields to behave in boolean form
bbb3c92 IPACM: fix compilation issue
1254fa1 IPACM: Add support for non IPA data path
48c4dd4 IPACM: add ethernet header for ipv6 DL traffic
9281509 IPACM: add support for CLANG compile
de812b4 Promotion of data.lnx.1.0-00023.
b8c5cad ipacm: Fix KW Errors
b4deebb Merge "IPACM: clean the modem UL rules after SSR"
2dd08ba Merge "IPACM: change src mac to bridge0"
254de9d IPACM: clean the modem UL rules after SSR
c251b38 Merge "IPACM: populate header handle"
25cef5e Merge "IPACM: fix ipv6 prefix problem"
2ee955c Merge "IPACM: Routing/Filtering support for IPAv3"
135b3da IPACM: populate header handle
37e0de9 IPACM: change src mac to bridge0
a26c8ec IPACM: fix ipv6 prefix problem
195d007 IPACM: wrong destination for ipv6 wan clients
0246824 Merge "IPACM: Fix to clean up default LL routes"
ff639a2 IPACM: Routing/Filtering support for IPAv3
deb2acb Merge "IPACM: Fix the UL traffic taking SW-exception"
bc093fe IPACM: Fix to clean up default LL routes
a3cc814 IPACM: Fix the UL traffic taking SW-exception
6003744 Merge "IPACM: Fix the ipv6-only AP+STA use-case"
5cbcdf9 Merge "Opt out	of clang till issues are fixed"
6d768a0 IPACM: Add support to get tether stats
06de5f1 IPACM: Fix the ipv6-only AP+STA use-case
b06d13d Opt out	of clang till issues are fixed
aec4d3a Merge "IPACM: Fix a check of mmap call"
6673fc3 Merge "IPACM: enable logging only for debug builds"
77158c4 Merge "IPACM: Handle NEIGH_EVENT for linklocal IP/IPv6 address"
b94558c IPACM: Handle NEIGH_EVENT for linklocal IP/IPv6 address
5a8c0fd IPACM: fix memory leak during client connect
9331f6e IPACM: Fix a check of mmap call
75da2ca IPACM: enable logging only for debug builds
b707257 Merge "IPACM: Fix the nat timeout update issue"
f9b4ce2 Merge "IPACM: fix the ipv6 rmnet-tethering FTP issue"
21c78b5 IPACM: Fix the nat timeout update issue
272a435 IPACM: Fix the compilation errors
3245b62 Merge "IPACM: Fix the nat iface missing when cfg change"
ea8df80 IPACM: fix the ipv6 rmnet-tethering FTP issue
b7bc7a8 Merge "IPACM: Handle new neighbor event"
fafb397 IPACM: Fix the nat iface missing when cfg change
fcfc079 Merge "IPACM: Fix the KW errors"
b10242a IPACM: Handle new neighbor event
db3f581 IPACM: fix icmpv4 filter rule not clean
3ca1627 Merge "IPACM: Handle AF_BRIDGE netlink message"
e75695a Merge "IPACM: Fix the filter index while deleting the rule"
cd1a76d IPACM: Fix the KW errors
6344d49 Merge "IPACM: fix incorrect filter index issue"
6d88f62 IPACM: fix incorrect filter index issue
5132d8c Merge "IPACM: fix lan2lan ipv6 issue"
db99143 IPACM: Handle AF_BRIDGE netlink message
d5611c7 IPACM: Fix the filter index while deleting the rule
5d2b750 Merge "IPACM: Suppor IPA stats update in ENFORCE mode"
600cc4b IPACM: fix lan2lan ipv6 issue
77a827e IPACM: Suppor IPA stats update in ENFORCE mode
a5af1b1 Merge "IPACM: Support ipv6 android tethering statistics"
848c918 Merge "IPACM: Code cleanup for the WLAN guest ap filtering rule"
c8488e1 Merge "IPACM: add TCP SYN/FIN/RST flt rules"
7a81cf6 IPACM: Support ipv6 android tethering statistics
b989026 IPACM: add TCP SYN/FIN/RST flt rules
004093c IPACM: Code cleanup for the WLAN guest ap filtering rule
5d3f2e8 IPACM: Support android tethering statistics
1b7a7a8 Merge "IPACM: Add error check while querying TX and RX properties"
aed53c4 Merge "IPACM: Enable meta-data in ICMP/ICMPv6 filtering rule on DL path"
7d83ed1 Merge "IPACM: Change the defualt access mode of WLAN interface"
7bd8f86 Merge "IPACM: Add support for HW path between Guest AP clients"
aa624e6 IPACM: Enable meta-data in ICMP/ICMPv6 filtering rule on DL path
445f2ca IPACM: Add error check while querying TX and RX properties
0f224e5 IPACM: Add support for HW path between Guest AP clients
e14d043 IPACM: Change the defualt access mode of WLAN interface
5cf6509 IPACM: Add  support for Ethernet bridge Mode
269ef41 IPACM: Fix the correct syntax for ODU configuration
e25e786 IPACM: Add initial support for HW path between CPE and USB clients
53251c6 Merge "IPACM: Delete nat entries from cache"
343fefc Merge "ipa : Addition of diag log messages for IPA NAT"
0f02b6d Merge "IPACM: Increase the neighbor mac cache"
bc9fa75 IPACM: Delete nat entries from cache
e6eecf7 IPACM: Increase the neighbor mac cache
421f006 ipa : Addition of diag log messages for IPA NAT
d2c7e32 Merge "msm: ipa: Compile ipacm for specific targets only"
0440891 Merge "IPACM: First AP+STA connection is taking sw path"
9b85a07 IPACM: First AP+STA connection is taking sw path
cb6a649 Merge "IPACM: Delete IPv6 filtering table when xlat PDN goes down"
cb36a6c msm: ipa: Compile ipacm for specific targets only
207927e Merge "IPACM: Fix for LAN ICMP and ICMPv6 traffic to take HW path"
e145724 IPACM: Fix for LAN ICMP and ICMPv6 traffic to take HW path
e861a01 IPACM: Delete IPv6 filtering table when xlat PDN goes down
82e8c94 Merge "IPACM: Add support for AP-AP mode with internet only guest profile"
53cfe0b IPACM: Add support for AP-AP mode with internet only guest profile
26ef486 Merge "IPACM: fix rndis/ecm routing rule missing"
8e64030 IPACM: fix rndis/ecm routing rule missing
b33445b Merge "IPACM: Add support for IHL based filtering of IPv6 fragement packets"
d5fa7a9 Merge "IPACM: fix the wlan MCC mode failed"
a03a3d7 Merge "IPACM: update dst mac address correctly"
a569b82 Merge "IPACM: fix the CPE client header issue"
5196ce7 IPACM: fix the wlan MCC mode failed
5fcbe90 Merge "IPACM: support CPE<->WLAN through Ethernet Bridging data path"
7fb9f9b Merge "IPACM: prevent crash if iface not register Tx/Rx property"
c3aabc9 IPACM: Add support for IHL based filtering of IPv6 fragement packets
f3223b2 IPACM: update dst mac address correctly
864f9da IPACM: support CPE<->WLAN through Ethernet Bridging data path
534cee8 IPACM: prevent crash if iface not register Tx/Rx property
7eae4c0 Merge "IPACM : Add support for the XLAT feature"
b6878a8 IPACM: fix the CPE client header issue
f18c791 Merge "IPACM: Add support for new WDI events"
67d90b4 Merge "IPACM: fix the configuration file missing issue"
03c76cd Merge "IPACM: Add change to make IPv4 ICMP traffic to take SW path"
4b58536 IPACM : Add support for the XLAT feature
43cf93d IPACM: Add change to make IPv4 ICMP traffic to take SW path
5a5b310 IPACM: Add support for new WDI events
14ccbc5 IPACM: fix the configuration file missing issue
ba5eefb Merge "IPACM: Add QMAP header in routing rule"
3759d35 Merge "IPACM: eMBMS traffic take offload path on ODU only"
602478e IPACM: Add QMAP header in routing rule
b13808c Merge "IPACM: resolve the compile issue on 8952"
5b11a25 Merge "IPACM: add flt rule counter on each prod client"
5c4ed51 Merge "IPACM: enable ipacm daemon for user build"
9532e63 Merge "IPACM: support external-AP running bridge mode"
61061e1 IPACM: resolve the compile issue on 8952
a2e5d95 Merge "IPACM: Add support for Ethernet bridging in MCC Mode"
01b3070 Merge "IPACM: add support for cradle in msmzirc"
b2d6cf9 IPACM: support external-AP running bridge mode
e00fad9 IPACM: add flt rule counter on each prod client
2912b25 IPACM: enable ipacm daemon for user build
367a1d2 IPACM: add support for cradle in msmzirc
bc0cbc8 IPACM: Add support for Ethernet bridging in MCC Mode
ca22ece Merge "IPACM: fix the cpe bootup crash issue"
ee56f1e Merge "IPACM: restore old connections when LTE up again"
f735509 IPACM: eMBMS traffic take offload path on ODU only
a8bce2c IPACM: fix the cpe bootup crash issue
8fa1c46 IPACM: restore old connections when LTE up again
d772db4 Merge "IPACM: fix external AP switch issue"
1ef6f33 Merge "IPACM: check if the upstream_route_add is expected"
f0c0448 Merge "IPACM: Remove meta data equation for ALG rules"
b181b7e IPACM: fix external AP switch issue
97ea9bd IPACM: check if the upstream_route_add is expected
c91d34c IPACM: Remove meta data equation for ALG rules
9dcd13f Merge "IPACM: Remove meta data equation for Ethernet bridging"
f20d7f8 Merge "IPACM : Set a unique name for each thread in ipacm"
86d787e Merge "IPACM: fix memory leak issue"
ccc12ed Merge "IPACM: fix the exception pipe issue in WAN interface"
ca08e94 Merge "IPACM:  Reset nat memory before posting init command"
de35e43 IPACM : Set a unique name for each thread in ipacm
c2d8533 IPACM: fix the exception pipe issue in WAN interface
f7de8e2 IPACM: Remove meta data equation for Ethernet bridging
3674f70 IPACM: fix memory leak issue
9fb80f6 IPACM:  Reset nat memory before posting init command
a96aeda Merge "IPACM: fix the IPv6 DL fragment packet issue"
d426f93 IPACM: fix the IPv6 DL fragment packet issue
524f777 Merge "IPACM: fix the embedded call issue in msmzirc"
936fd5d Merge "IPACM: support IPA_RM dependency for CPE project"
51203f8 Merge "IPACM: fix pointer init/free issue"
3df4de9 IPACM: fix the embedded call issue in msmzirc
19ef4cd Merge "IPACM: Change the TCP control filtering rule"
47d322e IPACM: fix pointer init/free issue
7a35164 Merge "IPACM: Handle no ALG ports case"
ecdf7a3 IPACM: Handle no ALG ports case
381d2e7 IPACM: Change the TCP control filtering rule
f59e9c4 IPACM: support IPA_RM dependency for CPE project
e9218d9 Merge "IPACM: fix modem assert issue after eMBMS goes down"
ee92e14 Merge "IPACM: add MCC/SCC switch support in ipacm"
f5efb4f IPACM: fix modem assert issue after eMBMS goes down
2b094f5 IPACM: add MCC/SCC switch support in ipacm
14f34c6 Merge "IPACM: fix ecm cradle mode unexpected link-down event"
ae0436d IPACM: fix ecm cradle mode unexpected link-down event
63c52f5 Merge "IPACM: fix the issue of missing first new neighbor message"
6d07433 Merge "IPACM: fix the issue of missing first new neighbor message"
b7c587d Merge "IPACM: Fix lan2lan RT rule failed issue"
e9d9b15 IPACM: fix the issue of missing first new neighbor message
ea725c4 Merge "IPACM: add support for Ethernet Bridging"
1f7e9ab Merge "IPACM: Fix IPv6 DL fragmented packet issue"
af8ebea IPACM: add support for Ethernet Bridging
e7824f7 Merge "IPACM: fix the exception pipe index"
392b33f Merge "IPACM: Increase the maximum number of modem UL filtering rules"
65a2990 IPACM: Fix lan2lan RT rule failed issue
273d5f6 IPACM: Fix IPv6 DL fragmented packet issue
a6a7021 IPACM: Increase the maximum number of modem UL filtering rules
89683ee Merge "Data compilation fix:"
8bff703 Data compilation fix:
69b032b IPACM: fix the exception pipe index
a48dcd3 Merge "IPACM: Fixes memory leak issue when wlan up/down"
af99b77 Merge "IPACM: Move ipacm.pid file to /data/misc/ipa"
f9397fa IPACM: Fixes memory leak issue when wlan up/down
55901d0 Merge "IPACM: Fixes IPA_RM dependency issue on cradle"
cca4f44 IPACM: Fixes IPA_RM dependency issue on cradle
a7ec26b Merge " IPACM: Fixes for Wi-Fi offload for AP-STA mode"
e13f5ee IPACM: Move ipacm.pid file to /data/misc/ipa
c63fb0e Merge "IPACM: Fix KW issue"
4f24417 Merge "IPACM: Fix RNDIS ipv6 ping issue"
c09b0f1  IPACM: Fixes for Wi-Fi offload for AP-STA mode
8098376 IPACM: Fix RNDIS ipv6 ping issue
377db1a IPACM: Fix KW issue
f0a69fe Merge "IPACM: support ODU project in LE"
fa4e388 IPACM: support ODU project in LE
0d977bd Merge "IPACM: move the socket location in Android"
543b701 Merge "IPACM: filter out AF_BRIDGE netlink message"
31762e1 IPACM: move the socket location in Android
2736e16 IPACM: filter out AF_BRIDGE netlink message
d0dd21c Merge "IPACM: change filter rule deletion order"
010b92e Merge "IPACM: Fix AP+STA mode FTP loca-subnet disconnect issue"
c059387 Merge "IPACM: speed up to construct wifi-client RT rules"
ccb6972 IPACM: speed up to construct wifi-client RT rules
2c7d962 IPACM: Fix AP+STA mode FTP loca-subnet disconnect issue
defdef0 IPACM: change filter rule deletion order
e36f332 Merge "ipanat: move ipaNatTable device node creation"
3d5511d Merge "ipanat: Add IPANT tests"
fa15031 Merge "IPACM: ignore SW-routing enable/disable msgs"
46f513e IPACM: ignore SW-routing enable/disable msgs
b1863ff Merge " Compile out for TARGET_USES_AOSP"
b2f6530 Merge "IPACM: Add dynamic support for swtiching between SW/HW path"
2ace013 ipanat: Add IPANT tests
244b846 IPACM: Add dynamic support for swtiching between SW/HW path
1630672 Merge "IPACM: get upstream and tethered iface in Android"
6b6b53b Merge "IPACM: Change the method for preventing multiple instances of ipacm"
785a59f Merge "IPACM: Clean the NAT rules before delete RT rules"
49e65ab ipanat: move ipaNatTable device node creation
d1e8dd8 IPACM: get upstream and tethered iface in Android
13fe7ba  Compile out for TARGET_USES_AOSP
6a1e1fc Merge "IPACM: not contruct rules in wlan STA mode for msm8994"
866dbb8 IPACM: Clean the NAT rules before delete RT rules
f31d506 IPACM: not contruct rules in wlan STA mode for msm8994
6f5c0bd IPACM: Change the method for preventing multiple instances of ipacm
585dc59 Merge "IPACM: Warn messages seen on Apps processor and follows the Data stall"
464d17b Merge "IPACM: workaround to get upstream iface from netlink"
13d56bf Merge "IPACM: Fix klocwork issue on master branch"
9fba0cf IPACM: workaround to get upstream iface from netlink
1db816f IPACM: Warn messages seen on Apps processor and follows the Data stall
e8c9d24 IPACM: Fix klocwork issue on master branch
87735cb Merge "IPACM: fix the index issue of incorrect modem UL filtering rule"
04998a1 Merge "IPANAT: fix for loop issue"
7c7b9f2 IPACM: fix the index issue of incorrect modem UL filtering rule
0ad0798 Merge "IPACM: add more ALG ports for Android platform"
5d10837 Merge "IPACM: Update QMAP ID in USB/WLAN pipes only for Internet PDN"
c56fc32 IPACM: add more ALG ports for Android platform
6290421 IPANAT: fix for loop issue
5b2d3ff IPACM: Update QMAP ID in USB/WLAN pipes only for Internet PDN
09f9bde Merge "IPACM: fix cradle mode plug-in/plug-out issue"
afd3444 Merge "IPACM: fix Q6 Rx rules not clean issue"
820aea6 Merge "IPACM: reduce the prints in QXDM"
f388580 IPACM: fix cradle mode plug-in/plug-out issue
ec90eb2 Merge "IPACM: Fix fragment exception rule should be first"
57c11b7 IPACM: reduce the prints in QXDM
b53825f IPACM: fix Q6 Rx rules not clean issue
670c6c3 IPACM: Fix fragment exception rule should be first
c451a9c Merge "IPACM: try to continue read msg from ipa-driver"
e9608f5 Merge "IPACM: fix IPv6 embedded call not working issue"
9c6dc9b Merge "IPACM: support upstream wan iface in Android"
5d3b03c IPACM: try to continue read msg from ipa-driver
7ac041a IPACM: fix IPv6 embedded call not working issue
2b78d90 Merge "IPACM: fix QXDM log not working in Android"
3c50380 Merge "IPANAT: remove the syslog usage"
d048888 Merge "IPACM: fix ipv6 rules issue for usb/wlan client"
5c05ce4 Merge "IPACM: Fix end2end ipv6 ping issue"
a77b544 IPACM: fix QXDM log not working in Android
ee2cd35 IPACM: support upstream wan iface in Android
4300e0b Merge "ipa-cfg-mgr: Add Android.mk files for IPACM and IPANAT"
a1d886d ipa-cfg-mgr: Add Android.mk files for IPACM and IPANAT
ebe3f62 Merge "IPACM: Add support for closing wwan_ioctl"
c800a6a Merge "IPACM: fix file descriptor issue"
43b4138 IPACM: fix ipv6 rules issue for usb/wlan client
c4a7135 IPACM: Fix end2end ipv6 ping issue
b367620 Merge "IPACM: fix crash issue in LE"
0bd8968 IPACM: fix crash issue in LE
025d3ad Merge "IPACM: add backup support to reset upstream iface"
9f22bea IPACM: add backup support to reset upstream iface
96deecd IPANAT: remove the syslog usage
2eeab69 IPACM: fix file descriptor issue
62ce019 Merge "IPACM: Fix conntrack event comes earlier than new neighbor"
8d6de24 Merge "IPACM: fix missing RTM_NEWNEIGH for WLAN channel change"
21f6687 IPACM: Fix conntrack event comes earlier than new neighbor
f69c46a IPACM: fix missing RTM_NEWNEIGH for WLAN channel change
209c08f Merge "IPACM: Fix IPv4 firewall not working issue"
bbe16ae IPACM: Fix IPv4 firewall not working issue
4a22524 Merge "IPACM: support QXDM diag via socket"
55f064d IPACM: support QXDM diag via socket
2225698 Merge "IPANAT: fix IPANAT deletion issue"
a664021 Merge "IPANAT: Fix checkpatch errors"
9110118 IPANAT: fix IPANAT deletion issue
c8e3c33 IPANAT: Fix checkpatch errors
ef6b669 IPACM: Add support for closing wwan_ioctl
9724bb8 Merge "IPACM: fix ipv6 ecm-backhaul issue"
0708393 Merge "IPACM: fix crash issue in Android"
288da49 IPACM: fix ipv6 ecm-backhaul issue
6cc1c79 IPACM: fix crash issue in Android
9819939 Merge "IPACM: support 8994 private subnet change"
8a61e2e Merge "IPACM: fix wlan-event issue from ipa-driver"
85968e6 IPACM: fix wlan-event issue from ipa-driver
18a55e0 IPACM: support 8994 private subnet change
76134e8 Merge "IPACM: add support for multi-PDN"
8780420 Merge "IPACM: read XML configuration for bridge name"
fc43b4d IPACM: add support for multi-PDN
1124056 IPACM: read XML configuration for bridge name
9e7caf9 Merge "IPACM: fix klocwork issue"
fcb575d IPACM: fix klocwork issue
30c1b45 Merge "IPACM: support usb dynamic config w.o plug-in/out"
5a569ca IPACM: support usb dynamic config w.o plug-in/out
f13f7ae Merge "IPACM: add conntrack optimization for lan2lan module"
d4d49c6 IPACM: add conntrack optimization for lan2lan module
ef15eec Merge "ipacm: CR652134 fix - Decreasing total_num_wifi_clients"
8adfae2 ipacm: CR652134 fix - Decreasing total_num_wifi_clients
87e61a0 Merge "IPANAT: fix AP+STA mode packets take SW path"
29eec61 IPANAT: fix AP+STA mode packets take SW path
c719700 Merge "IPACM: support dynamic ipacm configuration"
d3cf8bf IPACM: support dynamic ipacm configuration
f2b8209 Merge "IPACM: fix filtering rule index for WLAN APAP mode"
580dcfb IPACM: fix filtering rule index for WLAN APAP mode
a3347b2 Merge "IPACM: clean up q6 static UL filter rules"
58befd2 IPACM: clean up q6 static UL filter rules
f41c21e Merge "IPACM: fix v6 wan link-down up issue"
b728822 IPACM: fix v6 wan link-down up issue
e01e7e3 Merge "IPACM: fix wlan new_addr comes earlier issue"
316c852 IPACM: fix wlan new_addr comes earlier issue
2b7ae1b Merge "IPACM: fix WLAN mode switch and AP+STA mode STA LINK_DOWN issue"
3c708f5 IPACM: fix WLAN mode switch and AP+STA mode STA LINK_DOWN issue
25e0177 Merge "IPACM: Fix firewall rule IP address order problem"
1582b87 IPACM: Fix firewall rule IP address order problem
1a013dd Merge "IPACM: fix for lan2lan hw path"
5c36c2f IPACM: fix for lan2lan hw path
8849451 Merge "IPACM: enable LAN2LAN traffic using HW-path"
b371dda IPACM: enable LAN2LAN traffic using HW-path
58e5591 Merge "IPACM: handle multiple ETH usb clients"
071a9b3 Merge "IPACM: support multiple ETH usb clients"
4b2d725 IPACM: handle multiple ETH usb clients
8cc9c72 Merge "IPANAT: Not add embedded connections in AP+STA mode"
3d02680 IPANAT: Not add embedded connections in AP+STA mode
8f381e6 Merge "IPACM: avoid duplicate instance"
873cc34 Merge "IPACM: Fix NAT table didn't delete when LTE down"
1318fb1 IPACM: Fix NAT table didn't delete when LTE down
050cb17 IPACM: avoid duplicate instance
15deef6 Merge "IPACM: support 8994 linux Android build"
1247ec2 Merge "Include unistd.h"
2642ee0 Include unistd.h
346eeeb IPACM: support multiple ETH usb clients
b17124f IPACM: support 8994 linux Android build
4105bdb Merge "IPANAT: fix double NAT issue for embedded traffic"
db6ab80 Merge "IPACM: fix dynamic firewall rule issue"
150a82c Merge "IPACM: support IPA power save feature"
96232de Merge "IPACM: fix ipv6 backhaul up again crash issue"
ae94f35 IPACM: fix dynamic firewall rule issue
8c7397d IPANAT: fix double NAT issue for embedded traffic
d6a64e0 IPACM: fix ipv6 backhaul up again crash issue
b5e927c IPACM: support IPA power save feature
6031154 Merge "IPACM: fix v6 DL traffic going through SW path"
21f4e5e IPACM: fix v6 DL traffic going through SW path
3433990 Merge "IPANAT: fix nat entry is not clean when usb-client unplug"
c0089bc IPANAT: fix nat entry is not clean when usb-client unplug
945e148 Merge "PACM: fix missing RTM_NEWLINK for ECM disconnect"
6f4512a PACM: fix missing RTM_NEWLINK for ECM disconnect
2df7909 Merge "IPACM: remove a2_service related dependency"
135424d Merge "IPACM: fix no default route v4/v6 rule with Q6 backhaul"
3e301ab IPACM: remove a2_service related dependency
6ab27d4 IPACM: fix no default route v4/v6 rule with Q6 backhaul
182de2c Merge "IPACM: Fix for AP + STA mode"
82d7068 IPACM: Fix for AP + STA mode
80383af Merge "IPACM: fix firewall rule, ecm RT rule missing"
b02ce8e IPACM: fix firewall rule, ecm RT rule missing
8ab9b2b Merge "Fix rule index notification to modem: take into account the private subnet filtering rules"
cd1732e Fix rule index notification to modem: take into account the private subnet filtering rules
d3f4266 Merge "IPACM: Added support for 9x35 HW/SW architecture"
05ad9f3 IPACM: Added support for 9x35 HW/SW architecture
a1c9c9d Merge "IPACM: fix file-descriptor not clean issue"
bad7599 Merge "IPACM: fix lan/wan calloc free issue"
a9f45d3 IPACM: fix lan/wan calloc free issue
8dda3a9 IPACM: fix file-descriptor not clean issue
6def911 Merge "IPACM: increase netlink socket buffer size"
0a84f13 IPACM: increase netlink socket buffer size
38361ab Merge "IPACM: fix v6-firewall rule issue"
1a82ff2 IPACM: fix v6-firewall rule issue
d31030c Merge "IPACM: IPANAT changes for 9x35"
63b0a80 Merge "IPANAT fix: delete IPANAT entry when ECM client went away"
03b4ade Merge "ipanat: fix wifi-client reconnect nat miss"
e9f5938 IPANAT fix: delete IPANAT entry when ECM client went away
89d1ebe ipanat: fix wifi-client reconnect nat miss
57fbbb5 IPACM: IPANAT changes for 9x35
98bd07d Merge "IPACM: fix wlan client out of power-mode v6 issue"
7877ea1 IPACM: fix wlan client out of power-mode v6 issue
58089b1 Merge "IPACM: fix nat entries not clean in IPA hardware"
b7c1dd4 IPACM: fix nat entries not clean in IPA hardware
04f5273 Merge "IPACM: Fix wifi-client header not clean issue"
3be1d2a IPACM: Fix wifi-client header not clean issue
c5eca64 Merge "IPACM: delete dependency before free Rx-property"
4f5072b IPACM: delete dependency before free Rx-property
0b4716f Merge "IPACM:  delete dependency even wlan rules are not clean"
74c1d7b IPACM:  delete dependency even wlan rules are not clean
d84a338 Merge "IPACM: fix AP+STA mode header not clean issue"
44f01b5 IPACM: fix AP+STA mode header not clean issue
944c93f Merge "IPACM/IPANAT: Fix using syslog causing crash"
da7c82d IPACM/IPANAT: Fix using syslog causing crash
a1289c2 Merge "IPACM: fix NAT-rules deleted before RT-rules when power-save"
38c09d6 IPACM: fix NAT-rules deleted before RT-rules when power-save
f3bd1e6 Merge "Fix loop issue in IPANAT table"
a781bcc Fix loop issue in IPANAT table
3dc1e75 Merge "1.	Only interfaces that register rx or tx properties should be nat by ipahw 2.      Change NAT-logic in IPACM to only do NATTING for NAT-iface clients 3.      Instaed of blocking NON-NAT iface clients"
add7763 Merge "             1. update timeout for both tcp and udp connections              2. To update udp connections timeout value use ip_conntrack_udp_timeout_stream              3. To update tcp connection timeout value use ip_conntrack_tcp_timeout_established              4. Start inotify thread to read update udp/tcp timeout values""
34655b1 1.	Only interfaces that register rx or tx properties should be nat by ipahw 2.      Change NAT-logic in IPACM to only do NATTING for NAT-iface clients 3.      Instaed of blocking NON-NAT iface clients
3342e48              1. update timeout for both tcp and udp connections              2. To update udp connections timeout value use ip_conntrack_udp_timeout_stream              3. To update tcp connection timeout value use ip_conntrack_tcp_timeout_established              4. Start inotify thread to read update udp/tcp timeout values"
366a700 Merge "To fix kw errors"
c2df049 Merge "Listen for AP_disconnect/STA_disconnect from WLAN-Driver and post link-down event to IPACM CMD_queue"
a40f99f To fix kw errors
384df79 Listen for AP_disconnect/STA_disconnect from WLAN-Driver and post link-down event to IPACM CMD_queue
92881cd Merge "Create IPACM_ConntrackClient instance as part of global variable initialization to avoid race conditions"
cb4ce7f Merge "Create IPACM_ConntrackClient instance as part of global variable initialization to avoid race conditions"
d26fca0 Merge "Remove the hack in makefile, now IPACM will support dynamically both WLAN has RX_prop or none"
9cf6a54 Create IPACM_ConntrackClient instance as part of global variable initialization to avoid race conditions
371dbc4 Remove the hack in makefile, now IPACM will support dynamically both WLAN has RX_prop or none
f1e2f79 Merge "(1)	In ECM use-case, if doing fast plug-in/plug-out within 2s, the IPACM sometimes will crash due to rmnet0 didn't have TX-property, add checking there (2)	Event-dispatcher has some bugs when instance closes, somehow IPACM will access the freed memory location try to find next link-list cell"
9e47e84 (1)	In ECM use-case, if doing fast plug-in/plug-out within 2s, the IPACM sometimes will crash due to rmnet0 didn't have TX-property, add checking there (2)	Event-dispatcher has some bugs when instance closes, somehow IPACM will access the freed memory location try to find next link-list cell
2c125f5 Merge "(1) In AP+STA mode, if the default gw route event comes later than new_neighbor event for wlan0 (STA iface), IPACM received new_neighbor will check if header-construction is done already or not, won't insert multiple STA_header"
6fe0dc7 (1) In AP+STA mode, if the default gw route event comes later than new_neighbor event for wlan0 (STA iface), IPACM received new_neighbor will check if header-construction is done already or not, won't insert multiple STA_header
c7a21d0 Merge "(1) Support QCMAP feature: Guest_AP can.t talk to Primary_AP etc (2) Solution is to put all LAN traffic to A5"
b1dceb6 (1) Support QCMAP feature: Guest_AP can.t talk to Primary_AP etc (2) Solution is to put all LAN traffic to A5
f0470eb Merge "(1) support ECM plug/unplug behavior to configure/delete ECM related filter and routing rules without monitoring iface up/down. Current USB-team didn.t bring up/down ecm0 ifaces. (2) Solve the ECM usb-unplug, RT-rules are not clean issue."
686c676 (1) support ECM plug/unplug behavior to configure/delete ECM related filter and routing rules without monitoring iface up/down. Current USB-team didn.t bring up/down ecm0 ifaces. (2) Solve the ECM usb-unplug, RT-rules are not clean issue.
40295a4 Merge "Support ipv4 brdige0 changes, IPACM will get all wifi-client/ecm-client with ipv4-address coming from bridge0"
93a8d96 Support ipv4 brdige0 changes, IPACM will get all wifi-client/ecm-client with ipv4-address coming from bridge0
7285a48 Merge "Enabling sys log by default using start_ipacm_le script for more control"
014d447 Enabling sys log by default using start_ipacm_le script for more control
f1c3b34 Merge "Fixes for: (1) default wan filtering rule missing due to the mobileap_firewall.xml file is not specified. (2) add hack in IPACM to not add dependency between WLAN-RX endpoint to ECM/A2-Tx endpoints by only changing makefile in the future (AM_CPPFLAGS += -DWLAN_SW_RX)."
d9b927d Fixes for: (1) default wan filtering rule missing due to the mobileap_firewall.xml file is not specified. (2) add hack in IPACM to not add dependency between WLAN-RX endpoint to ECM/A2-Tx endpoints by only changing makefile in the future (AM_CPPFLAGS += -DWLAN_SW_RX).
ecce84a Merge "Don't overwrite mobileap_firewall.xml from QCMAP team"
cc3546f Merge "Support if wlan ipv4 new_addr comes earlier than AP_connect from WLAN_driver"
c0c3e5f Merge "1. adding sys log support 2. added dynamic enabled/disable file/sys log 3. added circular file log"
d778aca Merge "code changes for IPACM support A2-power-collapse by add/delete dependency between ifaces (A2/HSIC/ECM)"
003f942 Don't overwrite mobileap_firewall.xml from QCMAP team
129c14c Support if wlan ipv4 new_addr comes earlier than AP_connect from WLAN_driver
87b30d9 1. adding sys log support 2. added dynamic enabled/disable file/sys log 3. added circular file log
4367ae1 code changes for IPACM support A2-power-collapse by add/delete dependency between ifaces (A2/HSIC/ECM)
ee653a1 Merge "Enable nat entry in cache after adding nat entry successfully"
7484a35 Merge "Filter out rndis connections at user space not using netfilter conntrack filters"
270db22 Enable nat entry in cache after adding nat entry successfully
0920d49 Filter out rndis connections at user space not using netfilter conntrack filters
48c1c38 Merge "fix the ipv6 default route missing when v6 firewall rules appear"
2ba5eba Merge "Here is some code-change for 1. fix the header not clean issue in AP+STA mode for v6 2. checking the wifi client RT rule is setup or not when receive power-save mode to delete"
8ef5307 fix the ipv6 default route missing when v6 firewall rules appear
97293ae Here is some code-change for 1. fix the header not clean issue in AP+STA mode for v6 2. checking the wifi client RT rule is setup or not when receive power-save mode to delete
b966da7 Merge "This fix includes:"
67ae799 This fix includes:
c10fd7a Merge "Issue fixed:"
590f1f8 Merge "Fix the ipv6 default route"
339e031 Issue fixed:
77df222 Fix the ipv6 default route
35dcc1d Merge "From Skylar "There are some modification on netlink things to process new_neighbor messages, also IPACM_neighbor is to handle construct correct iface name. The WLAN changes will be 1. Duplicated table 2. Increase 2 filtering-rules which we discussed this afternoon""
3d7f2a2 From Skylar "There are some modification on netlink things to process new_neighbor messages, also IPACM_neighbor is to handle construct correct iface name. The WLAN changes will be 1. Duplicated table 2. Increase 2 filtering-rules which we discussed this afternoon"
3f20a2f Merge "Here is the fix for support wifi-client dynamically changing their ipv4 and IPACM will handle it when receive new_neighbor messages."
bf25d12 Here is the fix for support wifi-client dynamically changing their ipv4 and IPACM will handle it when receive new_neighbor messages.
6da8dfc Merge "Additional fixes from bringup:"
a15bf78 Merge "Fixes from bringup:"
4671a55 Additional fixes from bringup:
fdad00d Fixes from bringup:
76f9bfc Merge "Various fixes from bringup:"
5a9a114 Various fixes from bringup:
c1e7bca Merge "Various fixes from bring-up:"
4e23a83 Merge "Add ipv6 header config, firewall enhancement"
373d33d Various fixes from bring-up:
82e2b24 Merge "Use sanitized headers in data-ipa-cfg-mgr makefiles"
a1644d1 Add ipv6 header config, firewall enhancement
70267d3 Use sanitized headers in data-ipa-cfg-mgr makefiles
ef2ae2a Merge "Fix include path to point to sysroot"
04bdae7 Merge "Additional fixes from bring-up:"
18067b9 Additional fixes from bring-up:
17889f9 Fix include path to point to sysroot
fe84c85 Merge "Rename data-ipa to data-ipa-cfg-mgr to align with manifest path"
f487a7b Rename data-ipa to data-ipa-cfg-mgr to align with manifest path
1979fa8 Merge "Fixed crashes found during Bring up"
72c8c60 Fixed crashes found during Bring up
6e625fd Merge "Fixed below issues found during IPA bring up:"
402ba24 Fixed below issues found during IPA bring up:
ac1ba53 Merge "IPA configuration manager daemon and IPA NAT library."
5dcfae2 IPA configuration manager daemon and IPA NAT library.
ca61ebf Initial empty repository

Change-Id: Ic4ed12772b9ee5f4bf857a7496ae7b1400e7aeb4
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..fab2aff
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,3 @@
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = ipanat/src ipacm/src/
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..33164c0
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,57 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.65])
+AC_INIT(data-ipa, 1.0.0)
+AM_INIT_AUTOMAKE(data-ipa, 1.0.0)
+AC_OUTPUT(Makefile ipanat/src/Makefile ipacm/src/Makefile)
+AC_CONFIG_SRCDIR([ipanat/src/ipa_nat_drv.c])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+
+PKG_CHECK_MODULES([LIBXML], [libxml-2.0])
+AC_SUBST([LIBXML_CFLAGS])
+AC_SUBST([LIBXML_LIBS])
+
+# Checks for libraries.
+
+AC_ARG_WITH(sanitized-headers,
+      AS_HELP_STRING([--with-sanitized-headers=DIR],
+         [Specify the location of the sanitized Linux headers]),
+      [CPPFLAGS="$CPPFLAGS -idirafter $withval"])
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+	  
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h netinet/in.h sys/ioctl.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_OFF_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_CHECK_FUNCS([memset munmap])
+
+AC_OUTPUT
diff --git a/ipacm/inc/IPACM_CmdQueue.h b/ipacm/inc/IPACM_CmdQueue.h
new file mode 100644
index 0000000..27d7c8b
--- /dev/null
+++ b/ipacm/inc/IPACM_CmdQueue.h
@@ -0,0 +1,109 @@
+/*
+Copyright (c) 2013-2016, 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_CmdQueue.h
+
+	@brief
+	This file implements the IPAM Comment Queue definitions
+
+	@Author
+
+*/
+#ifndef IPA_CONNTRACK_MESSAGE_H
+#define IPA_CONNTRACK_MESSAGE_H
+
+#include <pthread.h>
+#include "IPACM_Defs.h"
+
+
+
+/*---------------------------------------------------------------------------
+	 Event data required by IPA_CM
+---------------------------------------------------------------------------*/
+
+
+typedef struct _ipacm_cmd_q_data {
+	ipa_cm_event_id event;
+	void *evt_data;
+}ipacm_cmd_q_data;
+
+typedef struct cmd_s
+{
+	void (*callback_ptr)(ipacm_cmd_q_data *);
+	ipacm_cmd_q_data data;
+}cmd_t;
+
+class Message
+{
+private:
+	Message *m_next;
+
+public:
+	cmd_t evt;
+
+	Message()
+	{
+		m_next = NULL;
+		evt.callback_ptr = NULL;
+	}
+	~Message() { }
+	void setnext(Message *item) { m_next = item; }
+	Message* getnext()       { return m_next; }
+};
+
+class MessageQueue
+{
+
+private:
+	Message *Head;
+	Message *Tail;
+	Message* dequeue(void);
+	static MessageQueue *inst_internal;
+	static MessageQueue *inst_external;
+
+	MessageQueue()
+	{
+		Head = NULL;
+		Tail = NULL;
+	}
+
+public:
+
+	~MessageQueue() { }
+	void enqueue(Message *item);
+
+	static void* Process(void *);
+	static MessageQueue* getInstanceInternal();
+	static MessageQueue* getInstanceExternal();
+
+};
+
+#endif  /* IPA_CONNTRACK_MESSAGE_H */
+
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
new file mode 100644
index 0000000..5bcb4eb
--- /dev/null
+++ b/ipacm/inc/IPACM_Config.h
@@ -0,0 +1,357 @@
+/*
+Copyright (c) 2013-2016, 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_Config.h
+
+	@brief
+	This file implements the IPACM Configuration from XML file
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_CONFIG_H
+#define IPACM_CONFIG_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_Xml.h"
+#include "IPACM_EvtDispatcher.h"
+
+typedef struct
+{
+  char iface_name[IPA_IFACE_NAME_LEN];
+}NatIfaces;
+
+/* for IPACM rm dependency use*/
+typedef struct _ipa_rm_client
+{
+    ipa_rm_resource_name producer_rm1;
+    ipa_rm_resource_name consumer_rm1;
+    ipa_rm_resource_name producer_rm2;
+    ipa_rm_resource_name consumer_rm2;
+    bool producer1_up;            /* only monitor producer_rm1, not monitor producer_rm2 */
+    bool consumer1_up;            /* only monitor consumer_rm1, not monitor consumer_rm2 */
+    bool rm_set;                  /* once producer1_up and consumer1_up, will add bi-directional dependency */
+    bool rx_bypass_ipa;          /* support WLAN may not register RX-property, should not add dependency */
+}ipa_rm_client;
+
+#define MAX_NUM_EXT_PROPS 25
+
+/* used to hold extended properties */
+typedef struct
+{
+	uint8_t num_ext_props;
+	ipa_ioc_ext_intf_prop prop[MAX_NUM_EXT_PROPS];
+} ipacm_ext_prop;
+
+/* iface */
+class IPACM_Config
+{
+public:
+
+	/* IPACM ipa_client map to rm_resource*/
+	ipa_rm_resource_name ipa_client_rm_map_tbl[IPA_CLIENT_MAX];
+
+	/* IPACM monitored rm_depency table */
+	ipa_rm_client ipa_rm_tbl[IPA_MAX_RM_ENTRY];
+
+	/* IPACM rm_depency a2 endpoint check*/
+	int ipa_rm_a2_check;
+
+	/* Store interested interface and their configuration from XML file */
+	ipa_ifi_dev_name_t *iface_table;
+
+	/* Store interested ALG port from XML file */
+	ipacm_alg *alg_table;
+
+	/* Store private subnet configuration from XML file */
+	ipa_private_subnet private_subnet_table[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+
+	/* Store the non nat iface names */
+	NatIfaces *pNatIfaces;
+
+	/* Store the bridge iface names */
+	char ipa_virtual_iface_name[IPA_IFACE_NAME_LEN];
+
+	/* Store the number of interface IPACM read from XML file */
+	int ipa_num_ipa_interfaces;
+
+	int ipa_num_private_subnet;
+
+	int ipa_num_alg_ports;
+
+	int ipa_nat_max_entries;
+
+	bool ipacm_odu_router_mode;
+
+	bool ipacm_odu_enable;
+
+	bool ipacm_odu_embms_enable;
+
+	bool ipacm_ip_passthrough_mode;
+
+	int ipa_nat_iface_entries;
+
+	/* Store the total number of wlan guest ap configured */
+	int ipa_num_wlan_guest_ap;
+
+	/* Max valid rm entry */
+	int ipa_max_valid_rm_entry;
+
+	/* Store SW-enable or not */
+	bool ipa_sw_rt_enable;
+
+	/* Store bridge mode or not */
+	bool ipa_bridge_enable;
+
+	/* Store bridge netdev mac */
+	uint8_t bridge_mac[IPA_MAC_ADDR_SIZE];
+
+	/* Store the flt rule count for each producer client*/
+	int flt_rule_count_v4[IPA_CLIENT_CONS - IPA_CLIENT_PROD];
+	int flt_rule_count_v6[IPA_CLIENT_CONS - IPA_CLIENT_PROD];
+
+	/* IPACM routing table name for v4/v6 */
+	struct ipa_ioc_get_rt_tbl rt_tbl_lan_v4, rt_tbl_wan_v4, rt_tbl_default_v4, rt_tbl_v6, rt_tbl_wan_v6;
+	struct ipa_ioc_get_rt_tbl rt_tbl_wan_dl;
+	struct ipa_ioc_get_rt_tbl rt_tbl_odu_v4, rt_tbl_odu_v6;
+
+	bool isMCC_Mode;
+
+	/* To return the instance */
+	static IPACM_Config* GetInstance();
+
+	const char* getEventName(ipa_cm_event_id event_id);
+
+	inline void increaseFltRuleCount(int index, ipa_ip_type iptype, int increment)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			flt_rule_count_v4[index] += increment;
+			IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+		}
+		else
+		{
+			flt_rule_count_v6[index] += increment;
+			IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+		}
+		return;
+	}
+
+	inline void decreaseFltRuleCount(int index, ipa_ip_type iptype, int decrement)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			flt_rule_count_v4[index] -= decrement;
+			IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+		}
+		else
+		{
+			flt_rule_count_v6[index] -= decrement;
+			IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+		}
+		return;
+	}
+
+	inline int getFltRuleCount(int index, ipa_ip_type iptype)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return -1;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			return flt_rule_count_v4[index];
+		}
+		else
+		{
+			return flt_rule_count_v6[index];
+		}
+	}
+
+	inline int GetAlgPortCnt()
+	{
+		return ipa_num_alg_ports;
+	}
+
+	int GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts);
+
+	inline int GetNatMaxEntries(void)
+	{
+		return ipa_nat_max_entries;
+	}
+
+	inline int GetNatIfacesCnt()
+	{
+		return ipa_nat_iface_entries;
+	}
+	int GetNatIfaces(int nPorts, NatIfaces *ifaces);
+
+	/* for IPACM resource manager dependency usage */
+	void AddRmDepend(ipa_rm_resource_name rm1,bool rx_bypass_ipa);
+
+	void DelRmDepend(ipa_rm_resource_name rm1);
+
+	int AddNatIfaces(char *dev_name);
+
+	int DelNatIfaces(char *dev_name);
+
+	inline void SetQmapId(uint8_t id)
+	{
+		qmap_id = id;
+	}
+
+	inline uint8_t GetQmapId()
+	{
+		return qmap_id;
+	}
+
+	int SetExtProp(ipa_ioc_query_intf_ext_props *prop);
+
+	ipacm_ext_prop* GetExtProp(ipa_ip_type ip_type);
+
+	int DelExtProp(ipa_ip_type ip_type);
+
+	int Init(void);
+
+	inline bool isPrivateSubnet(uint32_t ip_addr)
+	{
+		for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+		{
+			if(private_subnet_table[cnt].subnet_addr ==
+				 (private_subnet_table[cnt].subnet_mask & ip_addr))
+			{
+				return true;
+			}
+		}
+
+		return false;
+	}
+#ifdef FEATURE_IPA_ANDROID
+	inline bool AddPrivateSubnet(uint32_t ip_addr, int ipa_if_index)
+	{
+		ipacm_cmd_q_data evt_data;
+		ipacm_event_data_fid *data_fid;
+		uint32_t subnet_mask = ~0;
+		for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+		{
+			if(private_subnet_table[cnt].subnet_addr == ip_addr)
+			{
+				IPACMDBG("Already has private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, cnt);
+				return true;
+			}
+		}
+
+		if(ipa_num_private_subnet < IPA_MAX_PRIVATE_SUBNET_ENTRIES)
+		{
+			IPACMDBG("Add IPACM private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, ipa_num_private_subnet);
+			private_subnet_table[ipa_num_private_subnet].subnet_addr = ip_addr;
+			private_subnet_table[ipa_num_private_subnet].subnet_mask = (subnet_mask >> 8) << 8;
+			ipa_num_private_subnet++;
+
+			/* IPACM private subnet set changes */
+			data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_fid\n");
+				return IPACM_FAILURE;
+			}
+			data_fid->if_index = ipa_if_index; // already ipa index, not fid index
+			evt_data.event = IPA_PRIVATE_SUBNET_CHANGE_EVENT;
+			evt_data.evt_data = data_fid;
+
+			/* Insert IPA_PRIVATE_SUBNET_CHANGE_EVENT to command queue */
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+			return true;
+		}
+		IPACMERR("IPACM private subnet_addr overflow, total entry(%d)\n", ipa_num_private_subnet);
+		return false;
+	}
+
+	inline bool DelPrivateSubnet(uint32_t ip_addr, int ipa_if_index)
+	{
+		ipacm_cmd_q_data evt_data;
+		ipacm_event_data_fid *data_fid;
+		for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+		{
+			if(private_subnet_table[cnt].subnet_addr == ip_addr)
+			{
+				IPACMDBG("Found private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, cnt);
+				for (; cnt < ipa_num_private_subnet - 1; cnt++)
+				{
+					private_subnet_table[cnt].subnet_addr = private_subnet_table[cnt+1].subnet_addr;
+				}
+				ipa_num_private_subnet = ipa_num_private_subnet - 1;
+
+				/* IPACM private subnet set changes */
+				data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+				if(data_fid == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_fid\n");
+					return IPACM_FAILURE;
+				}
+				data_fid->if_index = ipa_if_index; // already ipa index, not fid index
+				evt_data.event = IPA_PRIVATE_SUBNET_CHANGE_EVENT;
+				evt_data.evt_data = data_fid;
+
+				/* Insert IPA_PRIVATE_SUBNET_CHANGE_EVENT to command queue */
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				return true;
+			}
+		}
+		IPACMDBG("can't find private subnet_addr as: 0x%x \n", ip_addr);
+		return false;
+	}
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+	static const char *DEVICE_NAME_ODU;
+
+private:
+	static IPACM_Config *pInstance;
+	static const char *DEVICE_NAME;
+	IPACM_Config(void);
+	int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+	uint8_t qmap_id;
+	ipacm_ext_prop ext_prop_v4;
+	ipacm_ext_prop ext_prop_v6;
+};
+
+#endif /* IPACM_CONFIG */
diff --git a/ipacm/inc/IPACM_ConntrackClient.h b/ipacm/inc/IPACM_ConntrackClient.h
new file mode 100644
index 0000000..a6076cf
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackClient.h
@@ -0,0 +1,104 @@
+/*
+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 IPACM_CONNTRACK_FILTER_H
+#define IPACM_CONNTRACK_FILTER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+
+#ifndef IPACM_DEBUG
+#define IPACM_DEBUG
+#endif
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+#include <sys/inotify.h>
+}
+
+using namespace std;
+
+#define UDP_TIMEOUT_UPDATE 20
+#define BROADCAST_IPV4_ADDR 0xFFFFFFFF
+
+class IPACM_ConntrackClient
+{
+
+private:
+   static IPACM_ConntrackClient *pInstance;
+
+   struct nfct_handle *tcp_hdl;
+   struct nfct_handle *udp_hdl;
+   struct nfct_filter *tcp_filter;
+   struct nfct_filter *udp_filter;
+   static int IPA_Conntrack_Filters_Ignore_Local_Addrs(struct nfct_filter *filter);
+   static int IPA_Conntrack_Filters_Ignore_Bridge_Addrs(struct nfct_filter *filter);
+   static int IPA_Conntrack_Filters_Ignore_Local_Iface(struct nfct_filter *, ipacm_event_iface_up *);
+   IPACM_ConntrackClient();
+
+public:
+   static int IPAConntrackEventCB(enum nf_conntrack_msg_type type,
+                                  struct nf_conntrack *ct,
+                                  void *data);
+
+   static int IPA_Conntrack_UDP_Filter_Init(void);
+   static int IPA_Conntrack_TCP_Filter_Init(void);
+   static void* TCPRegisterWithConnTrack(void *);
+   static void* UDPRegisterWithConnTrack(void *);
+   static void* UDPConnTimeoutUpdate(void *);
+
+   static void UpdateUDPFilters(void *, bool);
+   static void UpdateTCPFilters(void *, bool);
+   static void Read_TcpUdp_Timeout(char *in, int len);
+
+   static IPACM_ConntrackClient* GetInstance();
+
+#ifdef IPACM_DEBUG
+#define iptodot(X,Y) \
+		 IPACMLOG(" %s(0x%x): %d.%d.%d.%d\n", X, Y, ((Y>>24) & 0xFF), ((Y>>16) & 0xFF), ((Y>>8) & 0xFF), (Y & 0xFF));
+#endif
+
+#define log_nat(A,B,C,D,E,F) \
+		IPACMDBG_H("protocol %d Private IP: %d.%d.%d.%d\t Target IP: %d.%d.%d.%d\t private port: %d public port: %d %s",A,((B>>24) & 0xFF), ((B>>16) & 0xFF), ((B>>8) & 0xFF), (B & 0xFF), ((C>>24) & 0xFF), ((C>>16) & 0xFF),((C>>8) & 0xFF),(C & 0xFF),D,E,F);
+
+};
+
+#endif  /* IPACM_CONNTRACK_FILTER_H */
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
new file mode 100644
index 0000000..cdf3ef5
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2013-2016, 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 IPACM_CONNTRACK_LISTENER
+#define IPACM_CONNTRACK_LISTENER
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_Listener.h"
+#ifdef CT_OPT
+#include "IPACM_LanToLan.h"
+#endif
+
+#define MAX_IFACE_ADDRESS 50
+#define MAX_STA_CLNT_IFACES 10
+#define STA_CLNT_SUBNET_MASK 0xFFFFFF00
+
+using namespace std;
+
+typedef struct _nat_entry_bundle
+{
+	struct nf_conntrack *ct;
+	enum nf_conntrack_msg_type type;
+	nat_table_entry *rule;
+	bool isTempEntry;
+
+}nat_entry_bundle;
+
+class IPACM_ConntrackListener : public IPACM_Listener
+{
+
+private:
+	bool isCTReg;
+	bool isNatThreadStart;
+	bool WanUp;
+	NatApp *nat_inst;
+
+	int NatIfaceCnt;
+	int StaClntCnt;
+	NatIfaces *pNatIfaces;
+	uint32_t nat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
+	uint32_t nonnat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
+	uint32_t sta_clnt_ipv4_addr[MAX_STA_CLNT_IFACES];
+	IPACM_Config *pConfig;
+#ifdef CT_OPT
+	IPACM_LanToLan *p_lan2lan;
+#endif
+
+	void ProcessCTMessage(void *);
+	void ProcessTCPorUDPMsg(struct nf_conntrack *,
+	enum nf_conntrack_msg_type, u_int8_t);
+	void TriggerWANUp(void *);
+	void TriggerWANDown(uint32_t);
+	int  CreateNatThreads(void);
+	int  CreateConnTrackThreads(void);
+	bool AddIface(nat_table_entry *, bool *);
+	void AddORDeleteNatEntry(const nat_entry_bundle *);
+	void PopulateTCPorUDPEntry(struct nf_conntrack *, uint32_t, nat_table_entry *);
+	void CheckSTAClient(const nat_table_entry *, bool *);
+	int CheckNatIface(ipacm_event_data_all *, bool *);
+	void HandleNonNatIPAddr(void *, bool);
+
+#ifdef CT_OPT
+	void ProcessCTV6Message(void *);
+	void HandleLan2Lan(struct nf_conntrack *,
+		enum nf_conntrack_msg_type, nat_table_entry* );
+#endif
+
+public:
+	char wan_ifname[IPA_IFACE_NAME_LEN];
+	uint32_t wan_ipaddr;
+	bool isStaMode;
+	IPACM_ConntrackListener();
+	void event_callback(ipa_cm_event_id, void *data);
+	inline bool isWanUp()
+	{
+		return WanUp;
+	}
+
+	void HandleNeighIpAddrAddEvt(ipacm_event_data_all *);
+	void HandleNeighIpAddrDelEvt(uint32_t);
+	void HandleSTAClientAddEvt(uint32_t);
+	void HandleSTAClientDelEvt(uint32_t);
+};
+
+extern IPACM_ConntrackListener *CtList;
+
+#endif /* IPACM_CONNTRACK_LISTENER */
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
new file mode 100644
index 0000000..e50b316
--- /dev/null
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2013-2016, 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 IPACM_CONNTRACK_NATAPP_H
+#define IPACM_CONNTRACK_NATAPP_H
+
+#include <string.h>  /* for stderror */
+#include <stdlib.h>
+#include <cstdio>  /* for perror */
+
+#include "IPACM_Config.h"
+#include "IPACM_Xml.h"
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <ipa_nat_drv.h>
+}
+
+#define MAX_TEMP_ENTRIES 25
+
+#define IPACM_TCP_FULL_FILE_NAME  "/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established"
+#define IPACM_UDP_FULL_FILE_NAME   "/proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream"
+
+typedef struct _nat_table_entry
+{
+	uint32_t private_ip;
+	uint16_t private_port;
+
+	uint32_t target_ip;
+	uint16_t target_port;
+
+	uint32_t public_ip;
+	uint16_t public_port;
+
+	u_int8_t  protocol;
+	uint32_t timestamp;
+
+	bool dst_nat;
+	bool enabled;
+	uint32_t rule_hdl;
+
+}nat_table_entry;
+
+#define CHK_TBL_HDL()  if(nat_table_hdl == 0){ return -1; }
+
+class NatApp
+{
+private:
+
+	static NatApp *pInstance;
+
+	nat_table_entry *cache;
+	nat_table_entry temp[MAX_TEMP_ENTRIES];
+	uint32_t pub_ip_addr;
+	uint32_t pub_ip_addr_pre;
+	uint32_t nat_table_hdl;
+
+	int curCnt, max_entries;
+
+	ipacm_alg *pALGPorts;
+	uint16_t nALGPort;
+
+	uint32_t tcp_timeout;
+	uint32_t udp_timeout;
+
+	uint32_t PwrSaveIfs[IPA_MAX_NUM_WIFI_CLIENTS];
+
+	struct nf_conntrack *ct;
+	struct nfct_handle *ct_hdl;
+
+	NatApp();
+	int Init();
+
+	void UpdateCTUdpTs(nat_table_entry *, uint32_t);
+	bool ChkForDup(const nat_table_entry *);
+	bool isAlgPort(uint8_t, uint16_t);
+	void Reset();
+	bool isPwrSaveIf(uint32_t);
+
+public:
+	static NatApp* GetInstance();
+
+	int AddTable(uint32_t);
+	uint32_t GetTableHdl(uint32_t);
+	int DeleteTable(uint32_t);
+
+	int AddEntry(const nat_table_entry *);
+	int DeleteEntry(const nat_table_entry *);
+
+	void UpdateUDPTimeStamp();
+
+	int UpdatePwrSaveIf(uint32_t);
+	int ResetPwrSaveIf(uint32_t);
+	int DelEntriesOnClntDiscon(uint32_t);
+	int DelEntriesOnSTAClntDiscon(uint32_t);
+
+	void Read_TcpUdp_Timeout(void);
+
+	void AddTempEntry(const nat_table_entry *);
+	void CacheEntry(const nat_table_entry *);
+	void DeleteTempEntry(const nat_table_entry *);
+	void FlushTempEntries(uint32_t, bool, bool isDummy = false);
+};
+
+
+
+#endif /* IPACM_CONNTRACK_NATAPP_H */
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
new file mode 100644
index 0000000..d2cc362
--- /dev/null
+++ b/ipacm/inc/IPACM_Defs.h
@@ -0,0 +1,354 @@
+/*
+Copyright (c) 2013-2016, 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_Defs.h
+
+	@brief
+	This file implements the common definitions amon all ifaces.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPA_CM_DEFS_H
+#define IPA_CM_DEFS_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Log.h"
+
+#ifdef USE_GLIB
+#include <glib.h>
+#define strlcpy g_strlcpy
+#define strlcat g_strlcat
+#endif
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+}
+
+#define IF_NAME_LEN 16
+#define IPA_MAX_FILE_LEN  64
+#define IPA_IFACE_NAME_LEN 16
+#define IPA_ALG_PROTOCOL_NAME_LEN  10
+
+#define IPA_WLAN_PARTIAL_HDR_OFFSET  0 // dst mac first then src mac
+#define IPA_ODU_PARTIAL_HDR_OFFSET  8 // dst mac first then src mac
+#define IPA_WLAN_PARTIAL_HDR_NAME_v4  "IEEE802_3_v4"
+#define IPA_WLAN_PARTIAL_HDR_NAME_v6  "IEEE802_3_v6"
+#define IPA_DUMMY_ETH_HDR_NAME_v6     "ETH_dummy_v6"
+#define IPA_WAN_PARTIAL_HDR_NAME_v4  "IEEE802_3_STA_v4"
+#define IPA_WAN_PARTIAL_HDR_NAME_v6  "IEEE802_3_STA_v6"
+#define IPA_ETH_HDR_NAME_v4  "IPACM_ETH_v4"
+#define IPA_ETH_HDR_NAME_v6  "IPACM_ETH_v6"
+#define IPA_ODU_HDR_NAME_v4  "IPACM_ODU_v4"
+#define IPA_ODU_HDR_NAME_v6  "IPACM_ODU_v6"
+
+
+#define IPA_MAX_IFACE_ENTRIES 20
+#define IPA_MAX_PRIVATE_SUBNET_ENTRIES 3
+#define IPA_MAX_ALG_ENTRIES 20
+#define IPA_MAX_RM_ENTRY 6
+
+#define IPV4_ADDR_LINKLOCAL 0xA9FE0000
+#define IPV4_ADDR_LINKLOCAL_MASK 0xFFFF0000
+
+#define V4_DEFAULT_ROUTE_TABLE_NAME  "ipa_dflt_rt"
+#define V4_LAN_ROUTE_TABLE_NAME  "COMRTBLLANv4"
+#define V4_WAN_ROUTE_TABLE_NAME  "WANRTBLv4"
+#define WAN_DL_ROUTE_TABLE_NAME "ipa_dflt_wan_rt"
+#define V6_COMMON_ROUTE_TABLE_NAME  "COMRTBLv6"
+#define V6_WAN_ROUTE_TABLE_NAME  "WANRTBLv6"
+#define V4_ODU_ROUTE_TABLE_NAME  "ODURTBLv4"
+#define V6_ODU_ROUTE_TABLE_NAME  "ODURTBLv6"
+
+#define WWAN_QMI_IOCTL_DEVICE_NAME "/dev/wwan_ioctl"
+#define IPA_DEVICE_NAME "/dev/ipa"
+#define MAX_NUM_PROP 2
+
+#ifndef FEATURE_IPA_V3
+#define IPA_MAX_FLT_RULE 50
+#else
+#define IPA_MAX_FLT_RULE 100
+#endif
+
+#define TCP_FIN_SHIFT 16
+#define TCP_SYN_SHIFT 17
+#define TCP_RST_SHIFT 18
+#define NUM_IPV6_PREFIX_FLT_RULE 1
+
+/*---------------------------------------------------------------------------
+										Return values indicating error status
+---------------------------------------------------------------------------*/
+
+#define IPACM_SUCCESS                0         /* Successful operation   */
+#define IPACM_FAILURE               -1         /* Unsuccessful operation */
+
+#define IPACM_IP_NULL (ipa_ip_type)0xFF
+#define IPACM_INVALID_INDEX (ipa_ip_type)0xFF
+
+#define IPA_MAX_NUM_WIFI_CLIENTS  32
+#define IPA_MAX_NUM_WAN_CLIENTS  10
+#define IPA_MAX_NUM_ETH_CLIENTS  15
+#define IPA_MAX_NUM_AMPDU_RULE  15
+#define IPA_MAC_ADDR_SIZE  6
+
+/*===========================================================================
+										 GLOBAL DEFINITIONS AND DECLARATIONS
+===========================================================================*/
+typedef enum
+{
+	IPA_CFG_CHANGE_EVENT,                 /* NULL */
+	IPA_PRIVATE_SUBNET_CHANGE_EVENT,          /* ipacm_event_data_fid */
+	IPA_FIREWALL_CHANGE_EVENT,                /* NULL */
+	IPA_LINK_UP_EVENT,                        /* ipacm_event_data_fid */
+	IPA_LINK_DOWN_EVENT,                      /* ipacm_event_data_fid */
+	IPA_USB_LINK_UP_EVENT,                    /* ipacm_event_data_fid */
+	IPA_BRIDGE_LINK_UP_EVENT,                 /* ipacm_event_data_all */
+	IPA_WAN_EMBMS_LINK_UP_EVENT,              /* ipacm_event_data_mac */
+	IPA_ADDR_ADD_EVENT,                       /* ipacm_event_data_addr */
+	IPA_ADDR_DEL_EVENT,                       /* no use */
+	IPA_ROUTE_ADD_EVENT,                      /* ipacm_event_data_addr */
+	IPA_ROUTE_DEL_EVENT,                      /* ipacm_event_data_addr */
+	IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT,         /* ipacm_event_data_fid */
+	IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT,         /* ipacm_event_data_fid */
+	IPA_WLAN_AP_LINK_UP_EVENT,                /* ipacm_event_data_mac */
+	IPA_WLAN_STA_LINK_UP_EVENT,               /* ipacm_event_data_mac */
+	IPA_WLAN_LINK_DOWN_EVENT,                 /* ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_ADD_EVENT,                /* ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_ADD_EVENT_EX,             /* ipacm_event_data_wlan_ex */
+	IPA_WLAN_CLIENT_DEL_EVENT,                /* ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_POWER_SAVE_EVENT,         /* ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_RECOVER_EVENT,            /* ipacm_event_data_mac */
+	IPA_NEW_NEIGH_EVENT,                      /* ipacm_event_data_all */
+	IPA_DEL_NEIGH_EVENT,                      /* ipacm_event_data_all */
+	IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT,       /* ipacm_event_data_all */
+	IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT,       /* ipacm_event_data_all */
+	IPA_SW_ROUTING_ENABLE,                    /* NULL */
+	IPA_SW_ROUTING_DISABLE,                   /* NULL */
+	IPA_PROCESS_CT_MESSAGE,                   /* ipacm_ct_evt_data */
+	IPA_PROCESS_CT_MESSAGE_V6,                /* ipacm_ct_evt_data */
+	IPA_LAN_TO_LAN_NEW_CONNECTION,            /* ipacm_event_connection */
+	IPA_LAN_TO_LAN_DEL_CONNECTION,            /* ipacm_event_connection */
+	IPA_WLAN_SWITCH_TO_SCC,                   /* No Data */
+	IPA_WLAN_SWITCH_TO_MCC,                   /* No Data */
+	IPA_CRADLE_WAN_MODE_SWITCH,               /* ipacm_event_cradle_wan_mode */
+	IPA_WAN_XLAT_CONNECT_EVENT,               /* ipacm_event_data_fid */
+	IPA_TETHERING_STATS_UPDATE_EVENT,         /* ipacm_event_data_fid */
+	IPA_NETWORK_STATS_UPDATE_EVENT,           /* ipacm_event_data_fid */
+
+	IPA_EXTERNAL_EVENT_MAX,
+
+	IPA_HANDLE_WAN_UP,                        /* ipacm_event_iface_up  */
+	IPA_HANDLE_WAN_DOWN,                      /* ipacm_event_iface_up  */
+	IPA_HANDLE_WAN_UP_V6,                     /* NULL */
+	IPA_HANDLE_WAN_DOWN_V6,                   /* NULL */
+	IPA_HANDLE_WAN_UP_TETHER,                 /* ipacm_event_iface_up_tehter */
+	IPA_HANDLE_WAN_DOWN_TETHER,               /* ipacm_event_iface_up_tehter */
+	IPA_HANDLE_WAN_UP_V6_TETHER,              /* ipacm_event_iface_up_tehter */
+	IPA_HANDLE_WAN_DOWN_V6_TETHER,            /* ipacm_event_iface_up_tehter */
+	IPA_HANDLE_WLAN_UP,                       /* ipacm_event_iface_up */
+	IPA_HANDLE_LAN_UP,                        /* ipacm_event_iface_up */
+	IPA_ETH_BRIDGE_IFACE_UP,                  /* ipacm_event_eth_bridge*/
+	IPA_ETH_BRIDGE_IFACE_DOWN,                /* ipacm_event_eth_bridge*/
+	IPA_ETH_BRIDGE_CLIENT_ADD,                /* ipacm_event_eth_bridge */
+	IPA_ETH_BRIDGE_CLIENT_DEL,                /* ipacm_event_eth_bridge*/
+	IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH,       /* ipacm_event_eth_bridge*/
+	IPA_LAN_DELETE_SELF,                      /* ipacm_event_data_fid */
+	IPACM_EVENT_MAX
+} ipa_cm_event_id;
+
+typedef struct
+{
+	uint8_t num_rule;
+	uint32_t rule_hdl[MAX_NUM_PROP];
+} lan_to_lan_rt_rule_hdl;
+
+typedef enum
+{
+	LAN_IF = 0,
+	WLAN_IF,
+	WAN_IF,
+	VIRTUAL_IF,
+	ETH_IF,
+	EMBMS_IF,
+	ODU_IF,
+	UNKNOWN_IF
+} ipacm_iface_type;
+
+typedef enum
+{
+	ROUTER = 0,
+	BRIDGE
+} ipacm_cradle_iface_mode;
+
+typedef enum
+{
+	FULL,
+	INTERNET
+} ipacm_wlan_access_mode;
+
+typedef struct
+{
+	struct nf_conntrack *ct;
+	enum nf_conntrack_msg_type type;
+}ipacm_ct_evt_data;
+
+typedef struct
+{
+	char iface_name[IPA_IFACE_NAME_LEN];
+	ipacm_iface_type if_cat;
+	ipacm_cradle_iface_mode if_mode;
+	ipacm_wlan_access_mode wlan_mode;
+	int netlink_interface_index;
+} ipa_ifi_dev_name_t;
+
+typedef struct
+{
+	uint32_t subnet_addr;
+	uint32_t subnet_mask;
+} ipa_private_subnet;
+
+
+typedef struct _ipacm_event_data_all
+{
+	enum ipa_ip_type iptype;
+	int if_index;
+	uint32_t  ipv4_addr;
+	uint32_t  ipv6_addr[4];
+	uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+} ipacm_event_data_all;
+
+class IPACM_Lan;
+
+typedef struct
+{
+	ipacm_cradle_iface_mode cradle_wan_mode;
+} ipacm_event_cradle_wan_mode;
+
+typedef struct
+{
+	IPACM_Lan *p_iface;
+	ipa_ip_type iptype;
+	uint8_t mac_addr[6];
+} ipacm_event_eth_bridge;
+
+typedef struct
+{
+	enum ipa_ip_type iptype;
+	uint32_t src_ipv4_addr;
+	uint32_t dst_ipv4_addr;
+	uint32_t src_ipv6_addr[4];
+	uint32_t dst_ipv6_addr[4];
+} ipacm_event_connection;
+
+typedef struct _ipacm_event_data_fid
+{
+	int if_index;
+} ipacm_event_data_fid;
+
+typedef struct
+{
+	ipacm_iface_type if_cat;
+} ipacm_event_data_if_cat;
+
+typedef struct _ipacm_event_data_iptype
+{
+	int if_index;
+	int if_index_tether;
+	enum ipa_ip_type iptype;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+	uint32_t  ipv4_addr_gw;
+	uint32_t  ipv6_addr_gw[4];
+#endif
+} ipacm_event_data_iptype;
+
+
+typedef struct _ipacm_event_data_addr
+{
+	enum ipa_ip_type iptype;
+	int if_index;
+	uint32_t  ipv4_addr_gw;
+	uint32_t  ipv4_addr;
+	uint32_t  ipv4_addr_mask;
+	uint32_t  ipv6_addr[4];
+	uint32_t  ipv6_addr_mask[4];
+	uint32_t  ipv6_addr_gw[4];
+} ipacm_event_data_addr;
+
+typedef struct _ipacm_event_data_mac
+{
+	int if_index;
+	int ipa_if_cate;
+	uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+} ipacm_event_data_mac;
+
+typedef struct
+{
+	int if_index;
+	uint8_t num_of_attribs;
+	struct ipa_wlan_hdr_attrib_val attribs[0];
+} ipacm_event_data_wlan_ex;
+
+typedef struct _ipacm_event_iface_up
+{
+	char ifname[IPA_IFACE_NAME_LEN];
+	uint32_t ipv4_addr;
+	uint32_t addr_mask;
+	uint32_t ipv6_prefix[2];
+	bool is_sta;
+	uint8_t xlat_mux_id;
+}ipacm_event_iface_up;
+
+typedef struct _ipacm_event_iface_up_tether
+{
+	uint32_t if_index_tether;
+	uint32_t ipv6_prefix[2];
+	bool is_sta;
+}ipacm_event_iface_up_tehter;
+
+typedef enum
+{
+	Q6_WAN = 0,
+	WLAN_WAN,
+	ECM_WAN
+} ipacm_wan_iface_type;
+
+typedef struct _ipacm_ifacemgr_data
+{
+	int if_index;
+	ipacm_wan_iface_type if_type;
+	uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+}ipacm_ifacemgr_data;
+
+#endif /* IPA_CM_DEFS_H */
diff --git a/ipacm/inc/IPACM_EvtDispatcher.h b/ipacm/inc/IPACM_EvtDispatcher.h
new file mode 100644
index 0000000..550f4d4
--- /dev/null
+++ b/ipacm/inc/IPACM_EvtDispatcher.h
@@ -0,0 +1,76 @@
+/* 
+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_EvtDispatcher.h
+
+	@brief
+	This file implements the IPAM event dispatcher definitions
+
+	@Author
+
+*/
+#ifndef IPACM_EvtDispatcher_H
+#define IPACM_EvtDispatcher_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Listener.h"
+
+/* queue */
+typedef struct _cmd_evts
+{
+	ipa_cm_event_id event;
+	IPACM_Listener *obj;
+	//int ipa_interface_index;
+	_cmd_evts *next;
+}  cmd_evts;
+
+
+
+class IPACM_EvtDispatcher
+{
+public:
+
+	/* api for all iface instances to register events */
+	static int registr(ipa_cm_event_id event, IPACM_Listener *obj);
+
+	/* api for all iface instances to de-register events */
+	static int deregistr(IPACM_Listener *obj);
+
+	static int PostEvt(ipacm_cmd_q_data *);
+	static void ProcessEvt(ipacm_cmd_q_data *);
+
+private:
+	static cmd_evts *head;
+};
+
+#endif /* IPACM_EvtDispatcher_H */
diff --git a/ipacm/inc/IPACM_Filtering.h b/ipacm/inc/IPACM_Filtering.h
new file mode 100644
index 0000000..9bb8247
--- /dev/null
+++ b/ipacm/inc/IPACM_Filtering.h
@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2013-2016, 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_Filtering.h
+
+	@brief
+	This file implements the IPACM filtering definitions
+
+	@Author
+	Skylar Chang
+
+*/
+
+#ifndef IPACM_FILTERING_H
+#define IPACM_FILTERING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+#include <linux/rmnet_ipa_fd_ioctl.h>
+
+class IPACM_Filtering
+{
+public:
+	IPACM_Filtering();
+	~IPACM_Filtering();
+	bool AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable);
+	bool AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable);
+	bool DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable);
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+	bool DeviceNodeIsOpened();
+	bool DeleteFilteringHdls(uint32_t *flt_rule_hdls,
+													 ipa_ip_type ip,
+													 uint8_t num_rules);
+
+	bool AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id);
+	bool SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table);
+	bool ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable);
+	ipa_filter_action_enum_v01 GetQmiFilterAction(ipa_flt_action action);
+
+private:
+	static const char *DEVICE_NAME;
+	int fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_FILTERING_H
+
diff --git a/ipacm/inc/IPACM_Header.h b/ipacm/inc/IPACM_Header.h
new file mode 100644
index 0000000..027c8ff
--- /dev/null
+++ b/ipacm/inc/IPACM_Header.h
@@ -0,0 +1,70 @@
+/* 
+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.
+*/
+
+/*
+ * IPACM_Header.h
+ *
+ *  Created on: Jun 20, 2012
+ *      Author: tatias
+ */
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifndef IPACM_HEADER_H
+#define IPACM_HEADER_H
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+
+class IPACM_Header
+{
+private:
+	int m_fd;
+public:
+	bool AddHeader(struct ipa_ioc_add_hdr   *pHeaderTable);
+	bool DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTable);
+	bool GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct);
+	bool CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct);
+	bool Commit();
+	bool Reset();
+	bool DeleteHeaderHdl(uint32_t hdr_hdl);
+	bool AddHeaderProcCtx(struct ipa_ioc_add_hdr_proc_ctx* pHeader);
+	bool DeleteHeaderProcCtx(uint32_t hdl);
+
+	IPACM_Header();
+	~IPACM_Header();
+	bool DeviceNodeIsOpened();
+};
+
+
+#endif
+
+
diff --git a/ipacm/inc/IPACM_Iface.h b/ipacm/inc/IPACM_Iface.h
new file mode 100644
index 0000000..43b0da6
--- /dev/null
+++ b/ipacm/inc/IPACM_Iface.h
@@ -0,0 +1,153 @@
+/*
+Copyright (c) 2013-2016, 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_iface.h
+
+		@brief
+		This file implements the basis Iface definitions.
+
+		@Author
+		Skylar Chang
+
+*/
+#ifndef IPACM_IFACE_H
+#define IPACM_IFACE_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Header.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+#include <string.h>
+
+/* current support 2 ipv6-address*/
+#define MAX_DEFAULT_v4_ROUTE_RULES  1
+#define MAX_DEFAULT_v6_ROUTE_RULES  2
+#define IPV4_DEFAULT_FILTERTING_RULES 3
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPV6_DEFAULT_FILTERTING_RULES 6
+#else
+#define IPV6_DEFAULT_FILTERTING_RULES 3
+#endif
+
+#define IPV6_DEFAULT_LAN_FILTERTING_RULES 1
+#define IPV6_NUM_ADDR 3
+#define MAX_SOFTWAREROUTING_FILTERTING_RULES 2
+#define INVALID_IFACE -1
+
+/* iface */
+class IPACM_Iface :public IPACM_Listener
+{
+public:
+
+	/* Static class for reading IPACM configuration from XML file*/
+	static IPACM_Config *ipacmcfg;
+
+	/* IPACM interface id */
+	int ipa_if_num;
+
+	/* IPACM interface category */
+	ipacm_iface_type ipa_if_cate;
+
+	/* IPACM interface name */
+	char dev_name[IF_NAME_LEN];
+
+	/* IPACM interface iptype v4, v6 or both */
+	ipa_ip_type ip_type;
+
+	/* IPACM interface v6 ip-address*/
+	uint32_t ipv6_addr[MAX_DEFAULT_v6_ROUTE_RULES][4];
+
+	uint32_t software_routing_fl_rule_hdl[MAX_SOFTWAREROUTING_FILTERTING_RULES];
+
+	bool softwarerouting_act;
+
+	/* IPACM number of default route rules for ipv6*/
+	int num_dft_rt_v6;
+
+	uint32_t dft_v4fl_rule_hdl[IPV4_DEFAULT_FILTERTING_RULES];
+	uint32_t dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES];
+	/* create additional set of v6 RT-rules in Wanv6RT table*/
+	uint32_t dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+2*MAX_DEFAULT_v6_ROUTE_RULES];
+
+	ipa_ioc_query_intf *iface_query;
+	ipa_ioc_query_intf_tx_props *tx_prop;
+	ipa_ioc_query_intf_rx_props *rx_prop;
+
+	virtual int handle_down_evt() = 0;
+
+	virtual int handle_addr_evt(ipacm_event_data_addr *data) = 0;
+
+	IPACM_Iface(int iface_index);
+
+	virtual void event_callback(ipa_cm_event_id event,
+															void *data) = 0;
+
+	/* Query ipa_interface_index by given linux interface_index */
+	static int iface_ipa_index_query(int interface_index);
+
+	/* Query ipa_interface ipv4_addr by given linux interface_index */
+	static void iface_addr_query(int interface_index);
+
+	/*Query the IPA endpoint property */
+	int query_iface_property(void);
+
+	/*Configure the initial filter rules */
+	virtual int init_fl_rule(ipa_ip_type iptype);
+
+	/* Change IP Type.*/
+	void config_ip_type(ipa_ip_type iptype);
+
+	/* Get interface index */
+	virtual int ipa_get_if_index(char * if_name, int * if_index);
+
+	static IPACM_Routing m_routing;
+	static IPACM_Filtering m_filtering;
+	static IPACM_Header m_header;
+
+	/* software routing enable */
+	virtual int handle_software_routing_enable(void);
+
+	/* software routing disable */
+	virtual int handle_software_routing_disable(void);
+
+private:
+
+	static const char *DEVICE_NAME;
+};
+
+#endif /* IPACM_IFACE_H */
diff --git a/ipacm/inc/IPACM_IfaceManager.h b/ipacm/inc/IPACM_IfaceManager.h
new file mode 100644
index 0000000..c7184f2
--- /dev/null
+++ b/ipacm/inc/IPACM_IfaceManager.h
@@ -0,0 +1,90 @@
+/*
+Copyright (c) 2013-2016, 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_IfaceManager.h
+
+	@brief
+	This file implements the IPAM iface_manager definitions
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_IFACEMANAGER_H
+#define IPACM_IFACEMANAGER_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_INSTANCE_NOT_FOUND  0
+#define IPA_INSTANCE_FOUND  1
+
+/* queue */
+typedef struct _iface_instances
+{
+    /* Linux interface id */
+	int ipa_if_index;
+	IPACM_Listener *obj;
+	_iface_instances *next;
+}  iface_instances;
+
+
+class IPACM_IfaceManager : public IPACM_Listener
+{
+
+public:
+
+  IPACM_IfaceManager();
+
+  void event_callback(ipa_cm_event_id event,
+                      void *data);
+
+  /* api for all iface instances to de-register instances */
+  static int deregistr(IPACM_Listener *param);
+
+
+private:
+	int create_iface_instance(ipacm_ifacemgr_data *);
+
+    /* api to register instances */
+	int registr(int ipa_if_index, IPACM_Listener *obj);
+
+	int SearchInstance(int ipa_if_index);
+
+	static iface_instances *head;
+
+};
+
+#endif /* IPACM_IFACEMANAGER_H */
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
new file mode 100644
index 0000000..6c54f5e
--- /dev/null
+++ b/ipacm/inc/IPACM_Lan.h
@@ -0,0 +1,390 @@
+/*
+Copyright (c) 2013-2016, 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_Lan.h
+
+	@brief
+	This file implements the LAN iface definitions
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_LAN_H
+#define IPACM_LAN_H
+
+#include <stdio.h>
+#include <linux/msm_ipa.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Config.h"
+#include "IPACM_Conntrack_NATApp.h"
+
+#define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES  1
+#define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES  3
+#define IPA_NUM_ODU_ROUTE_RULES 2
+#define MAX_WAN_UL_FILTER_RULES MAX_NUM_EXT_PROPS
+#define NUM_IPV4_ICMP_FLT_RULE 1
+#define NUM_IPV6_ICMP_FLT_RULE 1
+
+/* ndc bandwidth ipatetherstats <ifaceIn> <ifaceOut> */
+/* <in->out_bytes> <in->out_pkts> <out->in_bytes> <out->in_pkts */
+
+#define PIPE_STATS "%s %s %lu %lu %lu %lu"
+#define IPA_PIPE_STATS_FILE_NAME "/data/misc/ipa/tether_stats"
+
+/* store each lan-iface unicast routing rule and its handler*/
+struct ipa_lan_rt_rule
+{
+	ipa_ip_type ip;
+	uint32_t v4_addr;
+	uint32_t v4_addr_mask;
+	uint32_t v6_addr[4];
+	uint32_t rt_rule_hdl[0];
+};
+
+/* Support multiple eth client */
+typedef struct _eth_client_rt_hdl
+{
+	uint32_t eth_rt_rule_hdl_v4;
+	uint32_t eth_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+	uint32_t eth_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}eth_client_rt_hdl;
+
+typedef struct _ipa_eth_client
+{
+	uint8_t mac[IPA_MAC_ADDR_SIZE];
+	uint32_t v4_addr;
+	uint32_t v6_addr[IPV6_NUM_ADDR][4];
+	uint32_t hdr_hdl_v4;
+	uint32_t hdr_hdl_v6;
+	bool route_rule_set_v4;
+	int route_rule_set_v6;
+	bool ipv4_set;
+	int ipv6_set;
+	bool ipv4_header_set;
+	bool ipv6_header_set;
+	eth_client_rt_hdl eth_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_eth_client;
+
+
+/* lan iface */
+class IPACM_Lan : public IPACM_Iface
+{
+public:
+
+	IPACM_Lan(int iface_index);
+	~IPACM_Lan();
+
+	/* store lan's wan-up filter rule handlers */
+	uint32_t lan_wan_fl_rule_hdl[IPA_WAN_DEFAULT_FILTER_RULE_HANDLES];
+
+	/* store private-subnet filter rule handlers */
+	uint32_t private_fl_rule_hdl[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+
+	/* LAN-iface's callback function */
+	void event_callback(ipa_cm_event_id event, void *data);
+
+	virtual int handle_wan_up(ipa_ip_type ip_type);
+
+	/* configure filter rule for wan_up event*/
+	virtual int handle_wan_up_ex(ipacm_ext_prop* ext_prop, ipa_ip_type iptype, uint8_t xlat_mux_id);
+
+	/* delete filter rule for wan_down event*/
+	virtual int handle_wan_down(bool is_sta_mode);
+
+	/* delete filter rule for wan_down event*/
+	virtual int handle_wan_down_v6(bool is_sta_mode);
+
+	/* configure private subnet filter rules*/
+	virtual int handle_private_subnet(ipa_ip_type iptype);
+
+	/* handle new_address event*/
+	int handle_addr_evt(ipacm_event_data_addr *data);
+
+	int handle_addr_evt_odu_bridge(ipacm_event_data_addr* data);
+
+	int handle_del_ipv6_addr(ipacm_event_data_all *data);
+
+	static bool odu_up;
+
+	/* install UL filter rule from Q6 */
+	virtual int handle_uplink_filter_rule(ipacm_ext_prop* prop, ipa_ip_type iptype, uint8_t xlat_mux_id);
+
+	int handle_cradle_wan_mode_switch(bool is_wan_bridge_mode);
+
+	int install_ipv4_icmp_flt_rule();
+
+
+	/* add header processing context and return handle to lan2lan controller */
+	int eth_bridge_add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_hdr_type, uint32_t *hdl);
+
+	/* add routing rule and return handle to lan2lan controller */
+	int eth_bridge_add_rt_rule(uint8_t *mac, char *rt_tbl_name, uint32_t hdr_proc_ctx_hdl,
+		ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int *rt_rule_count);
+
+	/* modify routing rule*/
+	int eth_bridge_modify_rt_rule(uint8_t *mac, uint32_t hdr_proc_ctx_hdl,
+		ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int rt_rule_count);
+
+	/* add filtering rule and return handle to lan2lan controller */
+	int eth_bridge_add_flt_rule(uint8_t *mac, uint32_t rt_tbl_hdl, ipa_ip_type iptype, uint32_t *flt_rule_hdl);
+
+	/* delete filtering rule */
+	int eth_bridge_del_flt_rule(uint32_t flt_rule_hdl, ipa_ip_type iptype);
+
+	/* delete routing rule */
+	int eth_bridge_del_rt_rule(uint32_t rt_rule_hdl, ipa_ip_type iptype);
+
+	/* delete header processing context */
+	int eth_bridge_del_hdr_proc_ctx(uint32_t hdr_proc_ctx_hdl);
+
+
+
+protected:
+
+	int each_client_rt_rule_count[IPA_IP_MAX];
+
+	uint32_t eth_bridge_flt_rule_offset[IPA_IP_MAX];
+
+	/* mac address has to be provided for client related events */
+	void eth_bridge_post_event(ipa_cm_event_id evt, ipa_ip_type iptype, uint8_t *mac);
+
+
+
+	virtual int add_dummy_private_subnet_flt_rule(ipa_ip_type iptype);
+
+	int handle_private_subnet_android(ipa_ip_type iptype);
+
+	int reset_to_dummy_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl);
+
+	virtual int install_ipv6_prefix_flt_rule(uint32_t* prefix);
+
+	virtual void delete_ipv6_prefix_flt_rule();
+
+	int install_ipv6_icmp_flt_rule();
+
+	void post_del_self_evt();
+
+	/* handle tethering stats */
+	int handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data);
+
+	/* handle tethering client */
+	int handle_tethering_client(bool reset, ipacm_client_enum ipa_client);
+
+	/* store ipv4 UL filter rule handlers from Q6*/
+	uint32_t wan_ul_fl_rule_hdl_v4[MAX_WAN_UL_FILTER_RULES];
+
+	/* store ipv6 UL filter rule handlers from Q6*/
+	uint32_t wan_ul_fl_rule_hdl_v6[MAX_WAN_UL_FILTER_RULES];
+
+	uint32_t ipv4_icmp_flt_rule_hdl[NUM_IPV4_ICMP_FLT_RULE];
+
+	uint32_t ipv6_prefix_flt_rule_hdl[NUM_IPV6_PREFIX_FLT_RULE];
+	uint32_t ipv6_icmp_flt_rule_hdl[NUM_IPV6_ICMP_FLT_RULE];
+
+	int num_wan_ul_fl_rule_v4;
+	int num_wan_ul_fl_rule_v6;
+
+	bool is_active;
+	bool modem_ul_v4_set;
+	bool modem_ul_v6_set;
+
+	uint32_t if_ipv4_subnet;
+
+	uint32_t ipv6_prefix[2];
+
+private:
+
+	/* get hdr proc ctx type given source and destination l2 hdr type */
+	ipa_hdr_proc_type eth_bridge_get_hdr_proc_type(ipa_hdr_l2_type t1, ipa_hdr_l2_type t2);
+
+	/* get partial header (header template of hdr proc ctx) */
+	int eth_bridge_get_hdr_template_hdl(uint32_t* hdr_hdl);
+
+
+	/* dynamically allocate lan iface's unicast routing rule structure */
+
+	bool is_mode_switch; /* indicate mode switch, need post internal up event */
+
+	int eth_client_len;
+
+	ipa_eth_client *eth_client;
+
+	int header_name_count;
+
+	int num_eth_client;
+
+	NatApp *Nat_App;
+
+	int ipv6_set;
+
+	uint32_t ODU_hdr_hdl_v4, ODU_hdr_hdl_v6;
+
+	uint32_t *odu_route_rule_v4_hdl;
+
+	uint32_t *odu_route_rule_v6_hdl;
+
+	bool ipv4_header_set;
+
+	bool ipv6_header_set;
+
+	inline ipa_eth_client* get_client_memptr(ipa_eth_client *param, int cnt)
+	{
+	    char *ret = ((char *)param) + (eth_client_len * cnt);
+		return (ipa_eth_client *)ret;
+	}
+
+	inline int get_eth_client_index(uint8_t *mac_addr)
+	{
+		int cnt;
+		int num_eth_client_tmp = num_eth_client;
+
+		IPACMDBG_H("Passed MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+						 mac_addr[0], mac_addr[1], mac_addr[2],
+						 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+		for(cnt = 0; cnt < num_eth_client_tmp; cnt++)
+		{
+			IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 get_client_memptr(eth_client, cnt)->mac[0],
+							 get_client_memptr(eth_client, cnt)->mac[1],
+							 get_client_memptr(eth_client, cnt)->mac[2],
+							 get_client_memptr(eth_client, cnt)->mac[3],
+							 get_client_memptr(eth_client, cnt)->mac[4],
+							 get_client_memptr(eth_client, cnt)->mac[5]);
+
+			if(memcmp(get_client_memptr(eth_client, cnt)->mac,
+								mac_addr,
+								sizeof(get_client_memptr(eth_client, cnt)->mac)) == 0)
+			{
+				IPACMDBG_H("Matched client index: %d\n", cnt);
+				return cnt;
+			}
+		}
+
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int delete_eth_rtrules(int clt_indx, ipa_ip_type iptype)
+	{
+		uint32_t tx_index;
+		uint32_t rt_hdl;
+		int num_v6;
+
+		if(iptype == IPA_IP_v4)
+		{
+		    for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		    {
+		        if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(eth_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+				{
+					IPACMDBG_H("Delete client index %d ipv4 RT-rules for tx:%d\n",clt_indx,tx_index);
+					rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4;
+
+					if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+					{
+						return IPACM_FAILURE;
+					}
+				}
+		    } /* end of for loop */
+
+		     /* clean the ipv4 RT rules for eth-client:clt_indx */
+		     if(get_client_memptr(eth_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+		     {
+				get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false;
+		     }
+		}
+
+		if(iptype == IPA_IP_v6)
+		{
+			for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+				{
+					for(num_v6 =0;num_v6 < get_client_memptr(eth_client, clt_indx)->route_rule_set_v6;num_v6++)
+					{
+						IPACMDBG_H("Delete client index %d ipv6 RT-rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+						rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+						if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+							{
+								return IPACM_FAILURE;
+							}
+
+							rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+							if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+							{
+								return IPACM_FAILURE;
+							}
+						}
+                    }
+		    } /* end of for loop */
+
+		    /* clean the ipv6 RT rules for eth-client:clt_indx */
+		    if(get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+		    {
+		        get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0;
+            }
+		}
+
+		return IPACM_SUCCESS;
+	}
+
+	/* handle eth client initial, construct full headers (tx property) */
+	int handle_eth_hdr_init(uint8_t *mac_addr);
+
+	/* handle eth client ip-address */
+	int handle_eth_client_ipaddr(ipacm_event_data_all *data);
+
+	/* handle eth client routing rule*/
+	int handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+	/*handle eth client del mode*/
+	int handle_eth_client_down_evt(uint8_t *mac_addr);
+
+	/* handle odu client initial, construct full headers (tx property) */
+	int handle_odu_hdr_init(uint8_t *mac_addr);
+
+	/* handle odu default route rule configuration */
+	int handle_odu_route_add();
+
+	/* handle odu default route rule deletion */
+	int handle_odu_route_del();
+
+	/*handle lan iface down event*/
+	int handle_down_evt();
+
+	/*handle reset usb-client rt-rules */
+	int handle_lan_client_reset_rt(ipa_ip_type iptype);
+};
+
+#endif /* IPACM_LAN_H */
diff --git a/ipacm/inc/IPACM_LanToLan.h b/ipacm/inc/IPACM_LanToLan.h
new file mode 100644
index 0000000..a28631e
--- /dev/null
+++ b/ipacm/inc/IPACM_LanToLan.h
@@ -0,0 +1,202 @@
+/*
+Copyright (c) 2014, 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.
+*/
+
+/*
+ * IPACM_LanToLan.h
+ *
+ *  Created on: Mar 4th, 2014
+ *      Author: Shihuan Liu
+ */
+
+#ifndef IPACM_LANTOLAN_H
+#define IPACM_LANTOLAN_H
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Lan.h"
+
+#ifdef FEATURE_IPA_ANDROID
+#include <libxml/list.h>
+#else/* defined(FEATURE_IPA_ANDROID) */
+#include <list>
+#endif /* ndefined(FEATURE_IPA_ANDROID)*/
+
+#define MAX_NUM_CACHED_CLIENT_ADD_EVENT 10
+#define MAX_NUM_IFACE 10
+#define MAX_NUM_CLIENT 16
+
+struct rt_rule_info
+{
+	int num_hdl[IPA_IP_MAX];	/* one client may need more than one routing rules on the same routing table depending on tx_prop */
+	uint32_t  rule_hdl[IPA_IP_MAX][MAX_NUM_PROP];
+};
+
+struct client_info
+{
+	uint8_t mac_addr[6];
+	rt_rule_info inter_iface_rt_rule_hdl[IPA_HDR_L2_MAX];	/* routing rule handles of inter interface communication based on source l2 header type */
+	rt_rule_info intra_iface_rt_rule_hdl;	/* routing rule handles of inter interface communication */
+};
+
+struct flt_rule_info
+{
+	client_info *p_client;
+	uint32_t flt_rule_hdl[IPA_IP_MAX];
+};
+
+struct peer_iface_info
+{
+	class IPACM_LanToLan_Iface *peer;
+	char rt_tbl_name_for_rt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+	char rt_tbl_name_for_flt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+	list<flt_rule_info> flt_rule;
+};
+
+class IPACM_LanToLan_Iface
+{
+public:
+	IPACM_LanToLan_Iface(IPACM_Lan *p_iface);
+	~IPACM_LanToLan_Iface();
+
+	void add_client_rt_rule_for_new_iface();
+
+	void add_all_inter_interface_client_flt_rule(ipa_ip_type iptype);
+
+	void add_all_intra_interface_client_flt_rule(ipa_ip_type iptype);
+
+	void handle_down_event();
+
+	void handle_wlan_scc_mcc_switch();
+
+	void handle_intra_interface_info();
+
+	void handle_new_iface_up(char rt_tbl_name_for_flt[][IPA_RESOURCE_NAME_MAX], char rt_tbl_name_for_rt[][IPA_RESOURCE_NAME_MAX],
+		IPACM_LanToLan_Iface *peer_iface);
+
+	void handle_client_add(uint8_t *mac);
+
+	void handle_client_del(uint8_t *mac);
+
+	void print_data_structure_info();
+
+	IPACM_Lan* get_iface_pointer();
+
+	bool get_m_is_ip_addr_assigned(ipa_ip_type iptype);
+
+	void set_m_is_ip_addr_assigned(ipa_ip_type iptype, bool value);
+
+	bool get_m_support_inter_iface_offload();
+
+	bool get_m_support_intra_iface_offload();
+
+	void increment_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type);
+
+	void decrement_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type);
+
+private:
+
+	IPACM_Lan *m_p_iface;
+	bool m_is_ip_addr_assigned[IPA_IP_MAX];
+	bool m_support_inter_iface_offload;
+	bool m_support_intra_iface_offload;
+
+	int ref_cnt_peer_l2_hdr_type[IPA_HDR_L2_MAX];	/* reference count of l2 header type of peer interfaces */
+	uint32_t hdr_proc_ctx_for_inter_interface[IPA_HDR_L2_MAX];
+	uint32_t hdr_proc_ctx_for_intra_interface;
+
+	list<client_info> m_client_info;	/* client list */
+	list<peer_iface_info> m_peer_iface_info;	/* peer information list */
+
+	/* The following members are for intra-interface communication*/
+	peer_iface_info m_intra_interface_info;
+
+	void add_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client);
+
+	void add_client_flt_rule(peer_iface_info *peer, client_info *client, ipa_ip_type iptype);
+
+	void del_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client);
+
+	void del_client_flt_rule(peer_iface_info *peer, client_info *client);
+
+	void add_client_rt_rule(peer_iface_info *peer, client_info *client);
+
+	void del_client_rt_rule(peer_iface_info *peer, client_info *client);
+
+	void clear_all_flt_rule_for_one_peer_iface(peer_iface_info *peer);
+
+	void clear_all_rt_rule_for_one_peer_iface(peer_iface_info *peer);
+
+	void add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type);
+
+	void del_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type);
+
+	void print_peer_info(peer_iface_info *peer_info);
+
+};
+
+class IPACM_LanToLan : public IPACM_Listener
+{
+
+public:
+
+	IPACM_LanToLan();
+
+private:
+
+	~IPACM_LanToLan();
+
+	list<class IPACM_LanToLan_Iface> m_iface;
+
+	list<ipacm_event_eth_bridge> m_cached_client_add_event;
+
+	void handle_iface_up(ipacm_event_eth_bridge *data);
+
+	void handle_iface_down(ipacm_event_eth_bridge *data);
+
+	void handle_client_add(ipacm_event_eth_bridge *data);
+
+	void handle_client_del(ipacm_event_eth_bridge *data);
+
+	void handle_wlan_scc_mcc_switch(ipacm_event_eth_bridge *data);
+
+	void handle_new_iface_up(IPACM_LanToLan_Iface *new_iface, IPACM_LanToLan_Iface *exist_iface);
+
+	void event_callback(ipa_cm_event_id event, void* param);
+
+	void handle_cached_client_add_event(IPACM_Lan *p_iface);
+
+	void clear_cached_client_add_event(IPACM_Lan *p_iface);
+
+	void print_data_structure_info();
+
+};
+
+#endif
diff --git a/ipacm/inc/IPACM_Listener.h b/ipacm/inc/IPACM_Listener.h
new file mode 100644
index 0000000..9d774fe
--- /dev/null
+++ b/ipacm/inc/IPACM_Listener.h
@@ -0,0 +1,54 @@
+/* 
+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_Listener.h
+
+	@brief
+	This file implements the abstract class notifier.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_LISTENER_H
+#define IPACM_LISTENER_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_CmdQueue.h"
+
+/* abstract class notifier */
+class IPACM_Listener
+{
+public:
+	virtual void event_callback(ipa_cm_event_id event,															void *data) = 0;
+	virtual ~IPACM_Listener(void) {};
+};
+
+#endif /* IPACM_LISTENER_H */
diff --git a/ipacm/inc/IPACM_Log.h b/ipacm/inc/IPACM_Log.h
new file mode 100644
index 0000000..dab0280
--- /dev/null
+++ b/ipacm/inc/IPACM_Log.h
@@ -0,0 +1,102 @@
+/*
+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.h
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+
+#ifndef IPACM_LOG_H
+#define IPACM_LOG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#define MAX_BUF_LEN 256
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPACMLOG_FILE "/dev/socket/ipacm_log_file"
+#else/* defined(FEATURE_IPA_ANDROID) */
+#define IPACMLOG_FILE "/etc/ipacm_log_file"
+#endif /* defined(NOT FEATURE_IPA_ANDROID)*/
+
+typedef struct ipacm_log_buffer_s {
+	char	user_data[MAX_BUF_LEN];
+} ipacm_log_buffer_t;
+
+void ipacm_log_send( void * user_data);
+
+static char buffer_send[MAX_BUF_LEN];
+static char dmesg_cmd[MAX_BUF_LEN];
+
+#define IPACMDBG_DMESG(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+								 snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s: " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+								 ipacm_log_send (buffer_send);\
+								 printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__); \
+								 memset(dmesg_cmd, 0, MAX_BUF_LEN);\
+								 snprintf(dmesg_cmd, MAX_BUF_LEN, "echo %s > /dev/kmsg", buffer_send);\
+								 system(dmesg_cmd);
+#ifdef DEBUG
+#define PERROR(fmt)   memset(buffer_send, 0, MAX_BUF_LEN);\
+					  snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+					  ipacm_log_send (buffer_send); \
+                      perror(fmt);
+#define IPACMERR(fmt, ...)	memset(buffer_send, 0, MAX_BUF_LEN);\
+							snprintf(buffer_send,MAX_BUF_LEN,"ERROR: %s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+							ipacm_log_send (buffer_send);\
+							printf("ERROR: %s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMDBG_H(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+							 snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+							 ipacm_log_send (buffer_send);\
+							 printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#else
+#define PERROR(fmt)   perror(fmt)
+#define IPACMERR(fmt, ...)   printf("ERR: %s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMDBG_H(fmt, ...) printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#endif
+#define IPACMDBG(fmt, ...)	printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMLOG(fmt, ...)  printf(fmt, ##__VA_ARGS__);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_LOG_H */
diff --git a/ipacm/inc/IPACM_Neighbor.h b/ipacm/inc/IPACM_Neighbor.h
new file mode 100644
index 0000000..14e86e5
--- /dev/null
+++ b/ipacm/inc/IPACM_Neighbor.h
@@ -0,0 +1,81 @@
+/* 
+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_Neighbor.h
+
+	@brief
+	This file implements the functionality of handling IPACM Neighbor events.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_NEIGHBOR_H
+#define IPACM_NEIGHBOR_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_MAX_NUM_NEIGHBOR_CLIENTS  100
+
+struct ipa_neighbor_client
+{
+	uint8_t mac_addr[6];
+	int iface_index;
+	uint32_t v4_addr;
+	int ipa_if_num;
+};
+
+class IPACM_Neighbor : public IPACM_Listener
+{
+
+public:
+
+	IPACM_Neighbor();
+
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+private:
+
+	int num_neighbor_client;
+
+	int circular_index;
+
+	ipa_neighbor_client neighbor_client[IPA_MAX_NUM_NEIGHBOR_CLIENTS];
+
+};
+
+#endif /* IPACM_NEIGHBOR_H */
diff --git a/ipacm/inc/IPACM_Netlink.h b/ipacm/inc/IPACM_Netlink.h
new file mode 100644
index 0000000..b0bdeb8
--- /dev/null
+++ b/ipacm/inc/IPACM_Netlink.h
@@ -0,0 +1,223 @@
+/* 
+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_Netlink.h
+
+	@brief
+	IPACM Netlink Messaging Implementation File
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_NETLINK_H
+#define IPACM_NETLINK_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
+#include <linux/netlink.h>
+#include <netinet/in.h>
+#include "IPACM_Defs.h"
+
+#define MAX_NUM_OF_FD 10
+#define IPA_NL_MSG_MAX_LEN (2048)
+
+/*--------------------------------------------------------------------------- 
+	 Type representing enumeration of NetLink event indication messages
+---------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------- 
+	 Types representing parsed NetLink message
+---------------------------------------------------------------------------*/
+#define IPA_NLA_PARAM_NONE        (0x0000)
+#define IPA_NLA_PARAM_PREFIXADDR  (0x0001)
+#define IPA_NLA_PARAM_LOCALADDR   (0x0002)
+#define IPA_NLA_PARAM_LABELNAME   (0x0004)
+#define IPA_NLA_PARAM_BCASTADDR   (0x0008)
+#define IPA_NLA_PARAM_ACASTADDR   (0x0010)
+#define IPA_NLA_PARAM_MCASTADDR   (0x0020)
+#define IPA_NLA_PARAM_CACHEINFO   (0x0080)
+#define IPA_NLA_PARAM_PROTOINFO   (0x0100)
+#define IPA_NLA_PARAM_FLAGS       (0x0200)
+
+#define IPA_RTA_PARAM_NONE        (0x0000)
+#define IPA_RTA_PARAM_DST         (0x0001)
+#define IPA_RTA_PARAM_SRC         (0x0002)
+#define IPA_RTA_PARAM_GATEWAY     (0x0004)
+#define IPA_RTA_PARAM_IIF         (0x0008)
+#define IPA_RTA_PARAM_OIF         (0x0010)
+#define IPA_RTA_PARAM_CACHEINFO   (0x0020)
+#define IPA_RTA_PARAM_PRIORITY    (0x0080)
+#define IPA_RTA_PARAM_METRICS     (0x0100)
+
+
+/*--------------------------------------------------------------------------- 
+	 Type representing function callback registered with a socket listener 
+	 thread for reading from a socket on receipt of an incoming message
+---------------------------------------------------------------------------*/
+typedef int (*ipa_sock_thrd_fd_read_f)(int fd);
+
+typedef enum
+{
+	IPA_INIT = 0,
+	IPA_LINK_UP_WAIT,
+	IPA_LINK_UP,
+	IPA_LINK_DOWN_WAIT,
+	IPA_LINK_DOWN
+} ipa_nl_state_e;
+
+typedef struct
+{
+	int sk_fd;
+	ipa_sock_thrd_fd_read_f read_func;
+} ipa_nl_sk_fd_map_info_t;
+
+typedef struct
+{
+	ipa_nl_sk_fd_map_info_t sk_fds[MAX_NUM_OF_FD];
+	fd_set fdset;
+	int num_fd;
+	int max_fd;
+} ipa_nl_sk_fd_set_info_t;
+
+typedef struct
+{
+	int                 sk_fd;       /* socket descriptor */
+	struct sockaddr_nl  sk_addr_loc; /* local address of socket */
+} ipa_nl_sk_info_t;
+
+typedef struct ipa_nl_addr_s {
+	struct sockaddr_storage        ip_addr;
+	unsigned int                   mask;
+} ipa_nl_addr_t;
+
+typedef struct ipa_nl_proto_info_s {
+	unsigned int                    param_mask;
+	unsigned int                    flags;
+	struct ifla_cacheinfo           cache_info;
+} ipa_nl_proto_info_t;
+
+typedef struct
+{
+	struct ifinfomsg  metainfo;                   /* from header */
+} ipa_nl_link_info_t;
+
+
+
+typedef struct ipa_nl_addr_info_s {
+	struct ifaddrmsg                metainfo;     /* from header */
+	struct                                      /* attributes  */
+	{
+		unsigned int                  param_mask;
+		unsigned char                 label_name[IF_NAME_LEN];
+		struct sockaddr_storage       prefix_addr;
+		struct sockaddr_storage       local_addr;
+		struct sockaddr_storage       bcast_addr;
+		struct sockaddr_storage       acast_addr;
+		struct sockaddr_storage       mcast_addr;
+	} attr_info;
+} ipa_nl_addr_info_t;
+
+
+typedef struct ipa_nl_neigh_info_s {
+	struct ndmsg                metainfo;     /* from header */
+	struct                                  /* attributes  */
+	{
+		unsigned int                param_mask;
+		struct sockaddr_storage     local_addr;
+		struct  sockaddr            lladdr_hwaddr;
+	} attr_info;
+} ipa_nl_neigh_info_t;
+
+
+
+typedef struct ipa_nl_route_info_s {
+	struct rtmsg                    metainfo;     /* from header */
+	struct                                      /* attributes  */
+	{
+		unsigned int                  param_mask;
+		struct sockaddr_storage       dst_addr;
+		struct sockaddr_storage       src_addr;
+		struct sockaddr_storage       gateway_addr;
+		struct sockaddr_storage       mark_addr;
+		struct rta_cacheinfo          cache_info;
+		__u32		iif_index;                      /* Link index  */
+		__u32		oif_index;                      /* Link index  */
+		__u32       priority;
+		__u32       metrics;
+		ipa_nl_proto_info_t        proto_info;
+	} attr_info;
+} ipa_nl_route_info_t;
+
+#define IPA_FLOW_TYPE_INVALID      (-1)
+
+typedef struct
+{
+	unsigned int type;
+	bool link_event;
+	/* Optional parameters */
+	ipa_nl_link_info_t      nl_link_info;
+	ipa_nl_addr_info_t      nl_addr_info;
+	ipa_nl_neigh_info_t      nl_neigh_info;
+	ipa_nl_route_info_t      nl_route_info;
+} ipa_nl_msg_t;
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+	 unsigned int nl_type,
+	 unsigned int nl_groups,
+	 ipa_nl_sk_fd_set_info_t *sk_fdset,
+	 ipa_sock_thrd_fd_read_f read_f
+	 );
+
+/*  Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd);
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_NETLINK_H */
diff --git a/ipacm/inc/IPACM_Routing.h b/ipacm/inc/IPACM_Routing.h
new file mode 100644
index 0000000..b5ffabc
--- /dev/null
+++ b/ipacm/inc/IPACM_Routing.h
@@ -0,0 +1,78 @@
+/*
+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_Routing.cpp
+
+	@brief
+	This file implements the IPACM routing functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+
+
+#ifndef IPACM_ROUTING_H
+#define IPACM_ROUTING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+
+using namespace std;
+
+class IPACM_Routing
+{
+public:
+	IPACM_Routing();
+	~IPACM_Routing();
+
+	bool AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable);
+	bool DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable);
+
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+
+	bool GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable);
+
+	bool DeviceNodeIsOpened();
+	bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
+
+	bool ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *);
+
+private:
+	static const char *DEVICE_NAME;
+	int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+
+	bool PutRoutingTable(uint32_t routingTableHandle);
+};
+
+#endif //IPACM_ROUTING_H
+
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
new file mode 100644
index 0000000..fe6d35e
--- /dev/null
+++ b/ipacm/inc/IPACM_Wan.h
@@ -0,0 +1,499 @@
+/*
+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_Wan.cpp
+
+	@brief
+	This file implements the WAN iface functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_WAN_H
+#define IPACM_WAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include <IPACM_Iface.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Xml.h>
+
+#define IPA_NUM_DEFAULT_WAN_FILTER_RULES 3 /*1 for v4, 2 for v6*/
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4 2
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6 6
+#else
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6 3
+#endif
+
+#define NETWORK_STATS "%s %lu %lu %lu %lu"
+#define IPA_NETWORK_STATS_FILE_NAME "/data/misc/ipa/network_stats"
+
+typedef struct _wan_client_rt_hdl
+{
+	uint32_t wan_rt_rule_hdl_v4;
+	uint32_t wan_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+	uint32_t wan_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}wan_client_rt_hdl;
+
+typedef struct _ipa_wan_client
+{
+	ipacm_event_data_wlan_ex* p_hdr_info;
+	uint8_t mac[IPA_MAC_ADDR_SIZE];
+	uint32_t v4_addr;
+	uint32_t v6_addr[IPV6_NUM_ADDR][4];
+	uint32_t hdr_hdl_v4;
+	uint32_t hdr_hdl_v6;
+	bool route_rule_set_v4;
+	int route_rule_set_v6;
+	bool ipv4_set;
+	int ipv6_set;
+	bool ipv4_header_set;
+	bool ipv6_header_set;
+	bool power_save_set;
+	wan_client_rt_hdl wan_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wan_client;
+
+/* wan iface */
+class IPACM_Wan : public IPACM_Iface
+{
+
+public:
+
+	static bool wan_up;
+	static bool wan_up_v6;
+	static uint8_t xlat_mux_id;
+	/* IPACM interface name */
+	static char wan_up_dev_name[IF_NAME_LEN];
+	static uint32_t curr_wan_ip;
+	IPACM_Wan(int, ipacm_wan_iface_type, uint8_t *);
+	virtual ~IPACM_Wan();
+
+	static bool isWanUP(int ipa_if_num_tether)
+	{
+#ifdef FEATURE_IPA_ANDROID
+		int i;
+		for (i=0; i < ipa_if_num_tether_v4_total;i++)
+		{
+			if (ipa_if_num_tether_v4[i] == ipa_if_num_tether)
+			{
+				IPACMDBG_H("support ipv4 tether_iface(%s)\n",
+					IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+				return wan_up;
+				break;
+			}
+		}
+		return false;
+#else
+		return wan_up;
+#endif
+	}
+
+	static bool isWanUP_V6(int ipa_if_num_tether)
+	{
+#ifdef FEATURE_IPA_ANDROID
+		int i;
+		for (i=0; i < ipa_if_num_tether_v6_total;i++)
+		{
+			if (ipa_if_num_tether_v6[i] == ipa_if_num_tether)
+			{
+				IPACMDBG_H("support ipv6 tether_iface(%s)\n",
+					IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+				return wan_up_v6;
+				break;
+			}
+		}
+		return false;
+#else
+		return wan_up_v6;
+#endif
+	}
+
+	static uint32_t getWANIP()
+	{
+		return curr_wan_ip;
+	}
+
+	static bool getXlat_Mux_Id()
+	{
+		return xlat_mux_id;
+	}
+
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+	static struct ipa_flt_rule_add flt_rule_v4[IPA_MAX_FLT_RULE];
+	static struct ipa_flt_rule_add flt_rule_v6[IPA_MAX_FLT_RULE];
+
+	static int num_v4_flt_rule;
+	static int num_v6_flt_rule;
+
+	ipacm_wan_iface_type m_is_sta_mode;
+	static bool backhaul_is_sta_mode;
+	static bool is_ext_prop_set;
+	static uint32_t backhaul_ipv6_prefix[2];
+
+	static bool embms_is_on;
+	static bool backhaul_is_wan_bridge;
+
+	static bool isWan_Bridge_Mode()
+	{
+		return backhaul_is_wan_bridge;
+	}
+#ifdef FEATURE_IPA_ANDROID
+	/* IPACM interface id */
+	static int ipa_if_num_tether_v4_total;
+	static int ipa_if_num_tether_v4[IPA_MAX_IFACE_ENTRIES];
+	static int ipa_if_num_tether_v6_total;
+	static int ipa_if_num_tether_v6[IPA_MAX_IFACE_ENTRIES];
+#endif
+
+private:
+
+	bool is_ipv6_frag_firewall_flt_rule_installed;
+	uint32_t ipv6_frag_firewall_flt_rule_hdl;
+	uint32_t *wan_route_rule_v4_hdl;
+	uint32_t *wan_route_rule_v6_hdl;
+	uint32_t *wan_route_rule_v6_hdl_a5;
+	uint32_t hdr_hdl_sta_v4;
+	uint32_t hdr_hdl_sta_v6;
+	uint32_t firewall_hdl_v4[IPACM_MAX_FIREWALL_ENTRIES];
+	uint32_t firewall_hdl_v6[IPACM_MAX_FIREWALL_ENTRIES];
+	uint32_t dft_wan_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+	uint32_t ipv6_dest_flt_rule_hdl[MAX_DEFAULT_v6_ROUTE_RULES];
+	int num_ipv6_dest_flt_rule;
+	uint32_t ODU_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+	int num_firewall_v4,num_firewall_v6;
+	uint32_t wan_v4_addr;
+	uint32_t wan_v4_addr_gw;
+	uint32_t wan_v6_addr_gw[4];
+	bool wan_v4_addr_set;
+	bool wan_v4_addr_gw_set;
+	bool wan_v6_addr_gw_set;
+	bool active_v4;
+	bool active_v6;
+	bool header_set_v4;
+	bool header_set_v6;
+	bool header_partial_default_wan_v4;
+	bool header_partial_default_wan_v6;
+	uint8_t ext_router_mac_addr[IPA_MAC_ADDR_SIZE];
+	uint8_t netdev_mac[IPA_MAC_ADDR_SIZE];
+
+	static int num_ipv4_modem_pdn;
+
+	static int num_ipv6_modem_pdn;
+
+	int modem_ipv4_pdn_index;
+
+	int modem_ipv6_pdn_index;
+
+	bool is_default_gateway;
+
+	uint32_t ipv6_prefix[2];
+
+	/* IPACM firewall Configuration file*/
+	IPACM_firewall_conf_t firewall_config;
+
+	/* STA mode wan-client*/
+	int wan_client_len;
+	ipa_wan_client *wan_client;
+	int header_name_count;
+	int num_wan_client;
+	uint8_t invalid_mac[IPA_MAC_ADDR_SIZE];
+	bool is_xlat;
+
+	/* update network stats for CNE */
+	int ipa_network_stats_fd;
+	uint32_t hdr_hdl_dummy_v6;
+	uint32_t hdr_proc_hdl_dummy_v6;
+
+	inline ipa_wan_client* get_client_memptr(ipa_wan_client *param, int cnt)
+	{
+	    char *ret = ((char *)param) + (wan_client_len * cnt);
+		return (ipa_wan_client *)ret;
+	}
+
+	inline int get_wan_client_index(uint8_t *mac_addr)
+	{
+		int cnt;
+		int num_wan_client_tmp = num_wan_client;
+
+		IPACMDBG_H("Passed MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+						 mac_addr[0], mac_addr[1], mac_addr[2],
+						 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+		for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+		{
+			IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 get_client_memptr(wan_client, cnt)->mac[0],
+							 get_client_memptr(wan_client, cnt)->mac[1],
+							 get_client_memptr(wan_client, cnt)->mac[2],
+							 get_client_memptr(wan_client, cnt)->mac[3],
+							 get_client_memptr(wan_client, cnt)->mac[4],
+							 get_client_memptr(wan_client, cnt)->mac[5]);
+
+			if(memcmp(get_client_memptr(wan_client, cnt)->mac,
+								mac_addr,
+								sizeof(get_client_memptr(wan_client, cnt)->mac)) == 0)
+			{
+				IPACMDBG_H("Matched client index: %d\n", cnt);
+				return cnt;
+			}
+		}
+
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int get_wan_client_index_ipv4(uint32_t ipv4_addr)
+	{
+		int cnt;
+		int num_wan_client_tmp = num_wan_client;
+
+		IPACMDBG_H("Passed IPv4 %x\n", ipv4_addr);
+
+		for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+		{
+			if (get_client_memptr(wan_client, cnt)->ipv4_set)
+			{
+				IPACMDBG_H("stored IPv4 %x\n", get_client_memptr(wan_client, cnt)->v4_addr);
+
+				if(ipv4_addr == get_client_memptr(wan_client, cnt)->v4_addr)
+				{
+					IPACMDBG_H("Matched client index: %d\n", cnt);
+					IPACMDBG_H("The MAC is %02x:%02x:%02x:%02x:%02x:%02x\n",
+							get_client_memptr(wan_client, cnt)->mac[0],
+							get_client_memptr(wan_client, cnt)->mac[1],
+							get_client_memptr(wan_client, cnt)->mac[2],
+							get_client_memptr(wan_client, cnt)->mac[3],
+							get_client_memptr(wan_client, cnt)->mac[4],
+							get_client_memptr(wan_client, cnt)->mac[5]);
+					IPACMDBG_H("header set ipv4(%d) ipv6(%d)\n",
+							get_client_memptr(wan_client, cnt)->ipv4_header_set,
+							get_client_memptr(wan_client, cnt)->ipv6_header_set);
+					return cnt;
+				}
+			}
+		}
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int get_wan_client_index_ipv6(uint32_t* ipv6_addr)
+	{
+		int cnt, v6_num;
+		int num_wan_client_tmp = num_wan_client;
+
+		IPACMDBG_H("Get ipv6 address 0x%08x.0x%08x.0x%08x.0x%08x\n", ipv6_addr[0], ipv6_addr[1], ipv6_addr[2], ipv6_addr[3]);
+
+		for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+		{
+			if (get_client_memptr(wan_client, cnt)->ipv6_set)
+			{
+			    for(v6_num=0;v6_num < get_client_memptr(wan_client, cnt)->ipv6_set;v6_num++)
+	            {
+
+					IPACMDBG_H("stored IPv6 0x%08x.0x%08x.0x%08x.0x%08x\n", get_client_memptr(wan_client, cnt)->v6_addr[v6_num][0],
+						get_client_memptr(wan_client, cnt)->v6_addr[v6_num][1],
+						get_client_memptr(wan_client, cnt)->v6_addr[v6_num][2],
+						get_client_memptr(wan_client, cnt)->v6_addr[v6_num][3]);
+
+					if(ipv6_addr[0] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][0] &&
+					   ipv6_addr[1] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][1] &&
+					   ipv6_addr[2]== get_client_memptr(wan_client, cnt)->v6_addr[v6_num][2] &&
+					   ipv6_addr[3] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][3])
+					{
+						IPACMDBG_H("Matched client index: %d\n", cnt);
+						IPACMDBG_H("The MAC is %02x:%02x:%02x:%02x:%02x:%02x\n",
+								get_client_memptr(wan_client, cnt)->mac[0],
+								get_client_memptr(wan_client, cnt)->mac[1],
+								get_client_memptr(wan_client, cnt)->mac[2],
+								get_client_memptr(wan_client, cnt)->mac[3],
+								get_client_memptr(wan_client, cnt)->mac[4],
+								get_client_memptr(wan_client, cnt)->mac[5]);
+						IPACMDBG_H("header set ipv4(%d) ipv6(%d)\n",
+								get_client_memptr(wan_client, cnt)->ipv4_header_set,
+								get_client_memptr(wan_client, cnt)->ipv6_header_set);
+						return cnt;
+					}
+				}
+			}
+		}
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int delete_wan_rtrules(int clt_indx, ipa_ip_type iptype)
+	{
+		uint32_t tx_index;
+		uint32_t rt_hdl;
+		int num_v6;
+
+		if(iptype == IPA_IP_v4)
+		{
+		     for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		     {
+		        if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(wan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+			{
+				IPACMDBG_H("Delete client index %d ipv4 Qos rules for tx:%d \n",clt_indx,tx_index);
+				rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4;
+
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+				{
+					return IPACM_FAILURE;
+				}
+			}
+		     } /* end of for loop */
+
+		     /* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+		     if(get_client_memptr(wan_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+		     {
+				get_client_memptr(wan_client, clt_indx)->route_rule_set_v4 = false;
+		     }
+		}
+
+		if(iptype == IPA_IP_v6)
+		{
+		    for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		    {
+
+				if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+				{
+					for(num_v6 =0;num_v6 < get_client_memptr(wan_client, clt_indx)->route_rule_set_v6;num_v6++)
+					{
+						IPACMDBG_H("Delete client index %d ipv6 Qos rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+						rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[num_v6];
+						if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+						{
+							return IPACM_FAILURE;
+						}
+
+						rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[num_v6];
+						if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+						{
+							return IPACM_FAILURE;
+						}
+					}
+
+				}
+			} /* end of for loop */
+
+		    /* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+		    if(get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+		    {
+		                 get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 = 0;
+                    }
+		}
+
+		return IPACM_SUCCESS;
+	}
+
+	int handle_wan_hdr_init(uint8_t *mac_addr);
+	int handle_wan_client_ipaddr(ipacm_event_data_all *data);
+	int handle_wan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+	/* handle new_address event */
+	int handle_addr_evt(ipacm_event_data_addr *data);
+
+	/* wan default route/filter rule configuration */
+	int handle_route_add_evt(ipa_ip_type iptype);
+
+	/* construct complete STA ethernet header */
+	int handle_sta_header_add_evt();
+
+	bool check_dft_firewall_rules_attr_mask(IPACM_firewall_conf_t *firewall_config);
+
+#ifdef FEATURE_IPA_ANDROID
+	/* wan posting supported tether_iface */
+	int post_wan_up_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether);
+
+	int post_wan_down_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether);
+#endif
+	int config_dft_firewall_rules(ipa_ip_type iptype);
+
+	/* configure the initial firewall filter rules */
+	int config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, ipa_ioc_add_flt_rule *pFilteringTable_v6);
+
+	int handle_route_del_evt(ipa_ip_type iptype);
+
+	int del_dft_firewall_rules(ipa_ip_type iptype);
+
+	int handle_down_evt();
+
+	/*handle wan-iface down event */
+	int handle_down_evt_ex();
+
+	/* wan default route/filter rule delete */
+	int handle_route_del_evt_ex(ipa_ip_type iptype);
+
+	/* configure the initial firewall filter rules */
+	int config_dft_firewall_rules_ex(struct ipa_flt_rule_add* rules, int rule_offset,
+		ipa_ip_type iptype);
+
+	/* init filtering rule in wan dl filtering table */
+	int init_fl_rule_ex(ipa_ip_type iptype);
+
+	/* add ICMP and ALG rules in wan dl filtering table */
+	int add_icmp_alg_rules(struct ipa_flt_rule_add* rules, int rule_offset, ipa_ip_type iptype);
+
+	/* query extended property */
+	int query_ext_prop();
+
+	ipa_ioc_query_intf_ext_props *ext_prop;
+
+	int config_wan_firewall_rule(ipa_ip_type iptype);
+
+	int del_wan_firewall_rule(ipa_ip_type iptype);
+
+	int add_dft_filtering_rule(struct ipa_flt_rule_add* rules, int rule_offset, ipa_ip_type iptype);
+
+	int install_wan_filtering_rule(bool is_sw_routing);
+
+	void change_to_network_order(ipa_ip_type iptype, ipa_rule_attrib* attrib);
+
+	bool is_global_ipv6_addr(uint32_t* ipv6_addr);
+
+	void handle_wlan_SCC_MCC_switch(bool, ipa_ip_type);
+
+	void handle_wan_client_SCC_MCC_switch(bool, ipa_ip_type);
+
+	int handle_network_stats_evt();
+
+	int m_fd_ipa;
+
+	int handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data);
+
+	/* construct dummy ethernet header */
+	int add_dummy_rx_hdr();
+};
+
+#endif /* IPACM_WAN_H */
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
new file mode 100644
index 0000000..eb911ac
--- /dev/null
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -0,0 +1,240 @@
+/*
+Copyright (c) 2013-2016, 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_Wlan.h
+
+		@brief
+		This file implements the WLAN iface functionality.
+
+		@Author
+		Skylar Chang
+
+*/
+#ifndef IPACM_WLAN_H
+#define IPACM_WLAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Lan.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Conntrack_NATApp.h"
+
+typedef struct _wlan_client_rt_hdl
+{
+	uint32_t wifi_rt_rule_hdl_v4;
+	uint32_t wifi_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+	uint32_t wifi_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}wlan_client_rt_hdl;
+
+typedef struct _ipa_wlan_client
+{
+	ipacm_event_data_wlan_ex* p_hdr_info;
+	uint8_t mac[IPA_MAC_ADDR_SIZE];
+	uint32_t v4_addr;
+	uint32_t v6_addr[IPV6_NUM_ADDR][4];
+	uint32_t hdr_hdl_v4;
+	uint32_t hdr_hdl_v6;
+	bool route_rule_set_v4;
+	int route_rule_set_v6;
+	bool ipv4_set;
+	int ipv6_set;
+	bool ipv4_header_set;
+	bool ipv6_header_set;
+	bool power_save_set;
+	wlan_client_rt_hdl wifi_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wlan_client;
+
+/* wlan iface */
+class IPACM_Wlan : public IPACM_Lan
+{
+
+public:
+
+	IPACM_Wlan(int iface_index);
+	virtual ~IPACM_Wlan(void);
+
+	static int total_num_wifi_clients;
+
+	void event_callback(ipa_cm_event_id event, void *data);
+
+	bool is_guest_ap();
+
+private:
+
+	bool m_is_guest_ap;
+
+	/* handle wlan access mode switch in ethernet bridging*/
+	void eth_bridge_handle_wlan_mode_switch();
+
+
+	int wlan_client_len;
+	ipa_wlan_client *wlan_client;
+
+	int header_name_count;
+	int num_wifi_client;
+
+	int wlan_ap_index;
+
+	static int num_wlan_ap_iface;
+
+	NatApp *Nat_App;
+
+	inline ipa_wlan_client* get_client_memptr(ipa_wlan_client *param, int cnt)
+	{
+	    char *ret = ((char *)param) + (wlan_client_len * cnt);
+		return (ipa_wlan_client *)ret;
+	}
+
+	inline int get_wlan_client_index(uint8_t *mac_addr)
+	{
+		int cnt;
+		int num_wifi_client_tmp = num_wifi_client;
+
+		IPACMDBG_H("Passed MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+						 mac_addr[0], mac_addr[1], mac_addr[2],
+						 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+		for(cnt = 0; cnt < num_wifi_client_tmp; cnt++)
+		{
+			IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 get_client_memptr(wlan_client, cnt)->mac[0],
+							 get_client_memptr(wlan_client, cnt)->mac[1],
+							 get_client_memptr(wlan_client, cnt)->mac[2],
+							 get_client_memptr(wlan_client, cnt)->mac[3],
+							 get_client_memptr(wlan_client, cnt)->mac[4],
+							 get_client_memptr(wlan_client, cnt)->mac[5]);
+
+			if(memcmp(get_client_memptr(wlan_client, cnt)->mac,
+								mac_addr,
+								sizeof(get_client_memptr(wlan_client, cnt)->mac)) == 0)
+			{
+				IPACMDBG_H("Matched client index: %d\n", cnt);
+				return cnt;
+			}
+		}
+
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int delete_default_qos_rtrules(int clt_indx, ipa_ip_type iptype)
+	{
+		uint32_t tx_index;
+		uint32_t rt_hdl;
+		int num_v6;
+
+		if(iptype == IPA_IP_v4)
+		{
+		     for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		     {
+		        if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+			{
+				IPACMDBG_H("Delete client index %d ipv4 Qos rules for tx:%d \n",clt_indx,tx_index);
+				rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+				{
+					return IPACM_FAILURE;
+				}
+			}
+		     } /* end of for loop */
+
+		     /* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+		     if(get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+		     {
+				get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+		     }
+		}
+
+		if(iptype == IPA_IP_v6)
+		{
+		    for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		    {
+
+				if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+				{
+					for(num_v6 =0;num_v6 < get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6;num_v6++)
+					{
+						IPACMDBG_H("Delete client index %d ipv6 Qos rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+						rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6];
+						if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+						{
+							return IPACM_FAILURE;
+						}
+
+						rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6];
+						if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+						{
+							return IPACM_FAILURE;
+						}
+					}
+
+				}
+			} /* end of for loop */
+
+		    /* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+		    if(get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+		    {
+		                 get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = 0;
+                    }
+		}
+
+		return IPACM_SUCCESS;
+	}
+
+	/* for handle wifi client initial,copy all partial headers (tx property) */
+	int handle_wlan_client_init_ex(ipacm_event_data_wlan_ex *data);
+
+	/*handle wifi client */
+	int handle_wlan_client_ipaddr(ipacm_event_data_all *data);
+
+	/*handle wifi client routing rule*/
+	int handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+	/*handle wifi client power-save mode*/
+	int handle_wlan_client_pwrsave(uint8_t *mac_addr);
+
+	/*handle wifi client del mode*/
+	int handle_wlan_client_down_evt(uint8_t *mac_addr);
+
+	/*handle wlan iface down event*/
+	int handle_down_evt();
+
+	/*handle reset wifi-client rt-rules */
+	int handle_wlan_client_reset_rt(ipa_ip_type iptype);
+
+	void handle_SCC_MCC_switch(ipa_ip_type);
+
+};
+
+
+#endif /* IPACM_WLAN_H */
diff --git a/ipacm/inc/IPACM_Xml.h b/ipacm/inc/IPACM_Xml.h
new file mode 100644
index 0000000..64c00ed
--- /dev/null
+++ b/ipacm/inc/IPACM_Xml.h
@@ -0,0 +1,303 @@
+/* 
+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_Xml.h
+
+  @brief
+  This file implements the XML specific parsing functionality.
+
+  @Author
+  Skylar Chang/Shihuan Liu
+
+*/
+#ifndef IPACM_XML_H
+#define IPACM_XML_H
+
+#include <linux/msm_ipa.h>
+#include "IPACM_Defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  
+#define IPACM_ASSERT(a)                                     \
+if (!(a)) {                                                 \
+	fprintf(stderr, "%s, %d: assertion (a) failed!",    \
+	__FILE__,                                           \
+	__LINE__);                                          \
+	abort();                                            \
+}
+  
+/* Max allowed size of the XML file (2 MB) */
+#define IPACM_XML_MAX_FILESIZE               (2 << 20)
+#define IPACM_MAX_FIREWALL_ENTRIES            50
+#define IPACM_IPV6_ADDR_LEN                   16
+
+/* Defines for clipping space or space & quotes (single, double) */
+#define IPACM_XML_CLIP_SPACE         " "
+#define IPACM_XML_CLIP_SPACE_QUOTES  " '\""
+
+#define MAX_XML_STR_LEN                 120
+  
+/* IPA Config Entries */
+#define system_TAG                           "system"
+#define ODU_TAG                              "ODUCFG"
+#define ODUMODE_TAG                          "OduMode"
+#define ODUEMBMS_OFFLOAD_TAG                 "eMBMS_offload"
+#define ODU_ROUTER_TAG                       "router"
+#define ODU_BRIDGE_TAG                       "bridge"
+#define IPACMCFG_TAG                         "IPACM"
+#define IPACMIFACECFG_TAG                    "IPACMIface"
+#define IFACE_TAG                            "Iface"
+#define NAME_TAG                             "Name"
+#define CATEGORY_TAG                         "Category"
+#define MODE_TAG                             "Mode"
+#define IPACMPRIVATESUBNETCFG_TAG            "IPACMPrivateSubnet"
+#define SUBNET_TAG                           "Subnet"
+#define SUBNETADDRESS_TAG                    "SubnetAddress"
+#define SUBNETMASK_TAG                       "SubnetMask"
+#define WANIF_TAG                            "WAN"
+#define LANIF_TAG                            "LAN"
+#define WLANIF_TAG                           "WLAN"
+#define WLAN_FULL_MODE_TAG                   "full"
+#define WLAN_INTERNET_MODE_TAG               "internet"
+#define WLAN_MODE_TAG                        "WlanMode"
+#define VIRTUALIF_TAG                        "VIRTUAL"
+#define UNKNOWNIF_TAG                        "UNKNOWN"
+#define ODUIF_TAG                            "ODU"
+#define EMBMSIF_TAG                          "EMBMS"
+#define ETHIF_TAG                            "ETH"
+#define IFACE_ROUTER_MODE_TAG                "ROUTER"
+#define IFACE_BRIDGE_MODE_TAG                "BRIDGE"
+#define IPACMALG_TAG                         "IPACMALG"
+#define ALG_TAG                              "ALG"
+#define Protocol_TAG                         "Protocol"
+#define Port_TAG                             "Port"
+#define TCP_PROTOCOL_TAG                     "TCP"
+#define UDP_PROTOCOL_TAG                     "UDP"
+
+/* FIREWALL Config Entries */
+#define Firewall_TAG                         "Firewall"
+#define MobileAPFirewallCfg_TAG              "MobileAPFirewallCfg"
+#define FirewallEnabled_TAG                  "FirewallEnabled"
+#define FirewallPktsAllowed_TAG              "FirewallPktsAllowed"
+
+#define IPFamily_TAG                         "IPFamily"
+#define IPV4SourceAddress_TAG                "IPV4SourceAddress"
+#define IPV4SourceIPAddress_TAG              "IPV4SourceIPAddress"
+#define IPV4SourceSubnetMask_TAG             "IPV4SourceSubnetMask"
+
+#define IPV4DestinationAddress_TAG           "IPV4DestinationAddress"
+#define IPV4DestinationIPAddress_TAG         "IPV4DestinationIPAddress"
+#define IPV4DestinationSubnetMask_TAG        "IPV4DestinationSubnetMask"
+
+#define IPV4TypeOfService_TAG                "IPV4TypeOfService"
+#define TOSValue_TAG                         "TOSValue"
+#define TOSMask_TAG                          "TOSMask"
+
+#define IPV4NextHeaderProtocol_TAG           "IPV4NextHeaderProtocol"
+
+#define IPV6SourceAddress_TAG                "IPV6SourceAddress"
+#define IPV6SourceIPAddress_TAG              "IPV6SourceIPAddress"
+#define IPV6SourcePrefix_TAG                 "IPV6SourcePrefix"
+
+#define IPV6DestinationAddress_TAG           "IPV6DestinationAddress"
+#define IPV6DestinationIPAddress_TAG         "IPV6DestinationIPAddress"
+#define IPV6DestinationPrefix_TAG            "IPV6DestinationPrefix"
+
+#define IPV6TrafficClass_TAG                 "IPV6TrafficClass"
+#define TrfClsValue_TAG                      "TrfClsValue"
+#define TrfClsMask_TAG                       "TrfClsMask"
+
+#define IPV6NextHeaderProtocol_TAG           "IPV6NextHeaderProtocol"
+
+#define TCPSource_TAG                        "TCPSource"
+#define TCPSourcePort_TAG                    "TCPSourcePort"
+#define TCPSourceRange_TAG                   "TCPSourceRange"
+
+#define TCPDestination_TAG                   "TCPDestination"
+#define TCPDestinationPort_TAG               "TCPDestinationPort"
+#define TCPDestinationRange_TAG              "TCPDestinationRange"
+
+#define UDPSource_TAG                        "UDPSource"
+#define UDPSourcePort_TAG                    "UDPSourcePort"
+#define UDPSourceRange_TAG                   "UDPSourceRange"
+
+#define UDPDestination_TAG                   "UDPDestination"
+#define UDPDestinationPort_TAG               "UDPDestinationPort"
+#define UDPDestinationRange_TAG              "UDPDestinationRange"
+
+#define ICMPType_TAG                         "ICMPType"
+#define ICMPCode_TAG                         "ICMPCode"
+
+#define ESP_TAG                              "ESP"
+#define ESPSPI_TAG                           "ESPSPI"
+
+#define TCP_UDPSource_TAG                    "TCP_UDPSource"
+#define TCP_UDPSourcePort_TAG                "TCP_UDPSourcePort"
+#define TCP_UDPSourceRange_TAG               "TCP_UDPSourceRange"
+
+#define TCP_UDPDestination_TAG               "TCP_UDPDestination"
+#define TCP_UDPDestinationPort_TAG           "TCP_UDPDestinationPort"
+#define TCP_UDPDestinationRange_TAG          "TCP_UDPDestinationRange"
+
+#define IPACMNat_TAG                         "IPACMNAT"
+#define NAT_MaxEntries_TAG                   "MaxNatEntries"
+
+#define IP_PassthroughFlag_TAG               "IPPassthroughFlag"
+#define IP_PassthroughMode_TAG               "IPPassthroughMode"
+
+/*---------------------------------------------------------------------------
+      IP protocol numbers - use in dss_socket() to identify protocols.
+      Also contains the extension header types for IPv6.
+---------------------------------------------------------------------------*/
+typedef enum
+{
+	IPACM_FIREWALL_IPV6_BASE_HDR        = 4,                               /* IPv6 Base Header           */
+	IPACM_FIREWALL_IPPROTO_HOP_BY_HOP_OPT_HDR = 0,                         /* Hop-by-hop Option Header   */
+	IPACM_FIREWALL_IPPROTO_ICMP         = 1,                               /* ICMP protocol */
+	IPACM_FIREWALL_IPPROTO_IGMP         = 2,                               /* IGMP protocol */
+	IPACM_FIREWALL_IPPROTO_IP           = IPACM_FIREWALL_IPV6_BASE_HDR,    /* IPv4          */
+	IPACM_FIREWALL_IPPROTO_TCP          = 6,                               /* TCP Protocol */
+	IPACM_FIREWALL_IPPROTO_UDP          = 17,                              /* UDP Protocol */
+	IPACM_FIREWALL_IPPROTO_IPV6         = 41,                              /* IPv6                       */
+	IPACM_FIREWALL_IPPROTO_ROUTING_HDR  = 43,                              /* Routing Header             */
+	IPACM_FIREWALL_IPPROTO_FRAG_HDR     = 44,                              /* Fragmentation Header       */
+	IPACM_FIREWALL_IPPROTO_GRE          = 47,                              /* GRE Protocol */
+	IPACM_FIREWALL_IPPROTO_ESP          = 50,                              /* ESP Protocol */
+	IPACM_FIREWALL_IPPROTO_AH           = 51,                              /* Authentication Header      */
+	IPACM_FIREWALL_IPPROTO_ICMP6        = 58,                              /* ICMPv6                     */
+	IPACM_FIREWALL_NO_NEXT_HDR          = 59,                              /* No Next Header for IPv6    */
+	IPACM_FIREWALL_IPPROTO_DEST_OPT_HDR = 60,                              /* Destination Options Header */
+	IPACM_FIREWALL_IPPROTO_MOBILITY_HDR = 135,                             /* Mobility Header            */
+	IPACM_FIREWALL_IPPROTO_TCP_UDP      = 253                              /* Unspecified protocol used for IPACM */
+} ipacm_firewall_ip_protocol_enum_type;
+
+/* define as mobileap firewall rule format*/
+typedef enum
+{
+	IP_V4 = 4,
+	IP_V6 = 6
+} firewall_ip_version_enum;
+  
+/*---------------------------------------------------------------------------
+           Extended FireWall Entry Configuration.
+---------------------------------------------------------------------------*/
+typedef struct
+{
+	struct ipa_rule_attrib attrib;
+	firewall_ip_version_enum  ip_vsn;
+} IPACM_extd_firewall_entry_conf_t;
+
+
+/*---------------------------------------------------------------------------
+           Extended FireWall configuration.
+---------------------------------------------------------------------------*/
+typedef union
+{
+	IPACM_extd_firewall_entry_conf_t extd_firewall_entry;
+} IPACM_extd_firewall_conf_t;
+
+
+typedef struct
+{
+	char firewall_config_file[IPA_MAX_FILE_LEN];
+	uint8_t  num_extd_firewall_entries;
+	IPACM_extd_firewall_entry_conf_t extd_firewall_entries[IPACM_MAX_FIREWALL_ENTRIES];
+	bool rule_action_accept;
+	bool firewall_enable;
+} IPACM_firewall_conf_t;
+  
+
+
+typedef struct
+{
+	uint8_t num_iface_entries;
+	ipa_ifi_dev_name_t iface_entries[IPA_MAX_IFACE_ENTRIES];
+} ipacm_iface_conf_t;
+
+typedef struct
+{
+	uint8_t num_subnet_entries;
+	ipa_private_subnet private_subnet_entries[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+} ipacm_private_subnet_conf_t;
+
+typedef struct
+{
+	uint8_t protocol;
+	uint16_t port;
+} ipacm_alg;
+
+typedef struct
+{
+	uint8_t num_alg_entries;
+	ipacm_alg alg_entries[IPA_MAX_ALG_ENTRIES];
+} ipacm_alg_conf_t;
+
+ 
+typedef struct  _IPACM_conf_t
+{
+	ipacm_iface_conf_t iface_config;
+	ipacm_private_subnet_conf_t private_subnet_config;
+	ipacm_alg_conf_t alg_config;
+	int nat_max_entries;
+	bool odu_enable;
+	bool router_mode_enable;
+	bool odu_embms_enable;
+	int num_wlan_guest_ap;
+	bool ip_passthrough_mode;
+} IPACM_conf_t;  
+
+/* This function read IPACM XML configuration*/
+int ipacm_read_cfg_xml
+(
+	char *xml_file,                              /* Filename and path     */
+	IPACM_conf_t *config                         /* Mobile AP config data */
+);
+
+/* This function reads QCMAP Firewall XML and store in IPACM Firewall stucture */
+int IPACM_read_firewall_xml
+(
+	char *xml_file,                                 /* Filename and path     */
+	IPACM_firewall_conf_t *config                   /* Mobile AP config data */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IPACM_XML
diff --git a/ipacm/src/Android.mk b/ipacm/src/Android.mk
new file mode 100644
index 0000000..9a4d659
--- /dev/null
+++ b/ipacm/src/Android.mk
@@ -0,0 +1,100 @@
+BOARD_PLATFORM_LIST := msm8916
+BOARD_PLATFORM_LIST += msm8909
+ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
+ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH)))
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../inc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ipanat/inc
+ifeq ($(call is-platform-sdk-version-at-least,20),true)
+LOCAL_C_INCLUDES += external/icu/icu4c/source/common
+else
+LOCAL_C_INCLUDES += external/icu4c/common
+endif
+LOCAL_C_INCLUDES += external/dhcpcd
+LOCAL_C_INCLUDES += external/libxml2/include
+LOCAL_C_INCLUDES += external/libnetfilter_conntrack/include
+LOCAL_C_INCLUDES += external/libnfnetlink/include
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+
+LOCAL_CFLAGS := -v
+LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DDEBUG
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),msmcobalt)
+LOCAL_CFLAGS += -DFEATURE_IPA_V3
+endif
+
+filetoadd = bionic/libc/kernel/arch-arm/asm/posix_types.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
+filetoadd = bionic/libc/kernel/arch-arm/asm/byteorder.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
+
+LOCAL_SRC_FILES := IPACM_Main.cpp \
+		IPACM_EvtDispatcher.cpp \
+		IPACM_Config.cpp \
+		IPACM_CmdQueue.cpp \
+		IPACM_Filtering.cpp \
+		IPACM_Routing.cpp \
+		IPACM_Header.cpp \
+		IPACM_Lan.cpp \
+		IPACM_Iface.cpp \
+		IPACM_Wlan.cpp \
+		IPACM_Wan.cpp \
+		IPACM_IfaceManager.cpp \
+		IPACM_Neighbor.cpp \
+		IPACM_Netlink.cpp \
+		IPACM_Xml.cpp \
+		IPACM_Conntrack_NATApp.cpp\
+		IPACM_ConntrackClient.cpp \
+		IPACM_ConntrackListener.cpp \
+                IPACM_Log.cpp
+
+LOCAL_MODULE := ipacm
+LOCAL_CLANG := false
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := libipanat
+LOCAL_SHARED_LIBRARIES += libxml2
+LOCAL_SHARED_LIBRARIES += libnfnetlink
+LOCAL_SHARED_LIBRARIES += libnetfilter_conntrack
+LOCAL_SHARED_LIBRARIES += libdhcpcd
+LOCAL_CLANG := true
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+define ADD_TEST
+
+include $(CLEAR_VARS)
+LOCAL_MODULE       := $1
+LOCAL_SRC_FILES    := $1
+LOCAL_MODULE_CLASS := ipacm
+LOCAL_MODULE_TAGS  := debug
+LOCAL_MODULE_PATH  := $(TARGET_OUT_ETC)
+include $(BUILD_PREBUILT)
+
+endef
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := IPACM_cfg.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_OWNER := ipacm
+include $(BUILD_PREBUILT)
+
+endif # $(TARGET_ARCH)
+endif
+endif
diff --git a/ipacm/src/IPACM_CmdQueue.cpp b/ipacm/src/IPACM_CmdQueue.cpp
new file mode 100644
index 0000000..a17fb08
--- /dev/null
+++ b/ipacm/src/IPACM_CmdQueue.cpp
@@ -0,0 +1,205 @@
+/* 
+Copyright (c) 2013-2016, 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_CmdQueue.cpp
+
+	@brief
+	This file implements the IPAM Comment Queue functionality
+
+	@Author 
+   Sunil
+
+*/
+#include <string.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Log.h"
+#include "IPACM_Iface.h"
+
+pthread_mutex_t mutex    = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t  cond_var = PTHREAD_COND_INITIALIZER;
+
+MessageQueue* MessageQueue::inst_internal = NULL;
+MessageQueue* MessageQueue::inst_external = NULL;
+
+MessageQueue* MessageQueue::getInstanceInternal()
+{
+	if(inst_internal == NULL)
+	{
+		inst_internal = new MessageQueue();
+		if(inst_internal == NULL)
+		{
+			IPACMERR("unable to create internal Message Queue instance\n");
+			return NULL;
+		}
+	}
+
+	return inst_internal;
+}
+
+MessageQueue* MessageQueue::getInstanceExternal()
+{
+	if(inst_external == NULL)
+	{
+		inst_external = new MessageQueue();
+		if(inst_external == NULL)
+		{
+			IPACMERR("unable to create external Message Queue instance\n");
+			return NULL;
+		}
+	}
+
+	return inst_external;
+}
+
+void MessageQueue::enqueue(Message *item)
+{
+	if(!Head)
+	{
+		Tail = item;
+		Head = item;
+	}
+	else
+	{
+		if(Tail == NULL)
+		{
+			IPACMDBG("Tail is null\n");
+			Head->setnext(item);
+		}
+		else
+		{
+			Tail->setnext(item);
+		}
+		Tail = item;
+	}
+}
+
+
+Message* MessageQueue::dequeue(void)
+{
+	if(Head == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		Message *tmp = Head;
+		Head = Head->getnext();
+
+		return tmp;
+	}
+}
+
+
+void* MessageQueue::Process(void *param)
+{
+	MessageQueue *MsgQueueInternal = NULL;
+	MessageQueue *MsgQueueExternal = NULL;
+	Message *item = NULL;
+	IPACMDBG("MessageQueue::Process()\n");
+
+	MsgQueueInternal = MessageQueue::getInstanceInternal();
+	if(MsgQueueInternal == NULL)
+	{
+		IPACMERR("unable to start internal cmd queue process\n");
+		return NULL;
+	}
+
+	MsgQueueExternal = MessageQueue::getInstanceExternal();
+	if(MsgQueueExternal == NULL)
+	{
+		IPACMERR("unable to start external cmd queue process\n");
+		return NULL;
+	}
+
+	while(1)
+	{
+		if(pthread_mutex_lock(&mutex) != 0)
+		{
+			IPACMERR("unable to lock the mutex\n");
+			return NULL;
+		}
+
+		item = MsgQueueInternal->dequeue();
+		if(item == NULL)
+		{
+			item = MsgQueueExternal->dequeue();
+			if(item)
+			{
+				IPACMDBG("Get event %s from external queue.\n",
+					IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
+			}
+		}
+		else
+		{
+			IPACMDBG("Get event %s from internal queue.\n",
+				IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
+		}
+
+		if(item == NULL)
+		{
+			IPACMDBG("Waiting for Message\n");
+
+			if(pthread_cond_wait(&cond_var, &mutex) != 0)
+			{
+				IPACMERR("unable to lock the mutex\n");
+
+				if(pthread_mutex_unlock(&mutex) != 0)
+				{
+					IPACMERR("unable to unlock the mutex\n");
+					return NULL;
+				}
+
+				return NULL;
+			}
+
+			if(pthread_mutex_unlock(&mutex) != 0)
+			{
+				IPACMERR("unable to unlock the mutex\n");
+				return NULL;
+			}
+
+		}
+		else
+		{
+			if(pthread_mutex_unlock(&mutex) != 0)
+			{
+				IPACMERR("unable to unlock the mutex\n");
+				return NULL;
+			}
+
+			IPACMDBG("Processing item %p event ID: %d\n",item,item->evt.data.event);
+			item->evt.callback_ptr(&item->evt.data);
+			delete item;
+			item = NULL;
+		}
+
+	} /* Go forever until a termination indication is received */
+
+}
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
new file mode 100644
index 0000000..eb30e0f
--- /dev/null
+++ b/ipacm/src/IPACM_Config.cpp
@@ -0,0 +1,816 @@
+/*
+Copyright (c) 2013-2016, 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_Config.cpp
+
+		@brief
+		This file implements the IPACM Configuration from XML file
+
+		@Author
+		Skylar Chang
+
+*/
+#include <IPACM_Config.h>
+#include <IPACM_Log.h>
+#include <IPACM_Iface.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+IPACM_Config *IPACM_Config::pInstance = NULL;
+const char *IPACM_Config::DEVICE_NAME = "/dev/ipa";
+const char *IPACM_Config::DEVICE_NAME_ODU = "/dev/odu_ipa_bridge";
+
+#define __stringify(x...) #x
+
+const char *ipacm_event_name[] = {
+	__stringify(IPA_CFG_CHANGE_EVENT),                     /* NULL */
+	__stringify(IPA_PRIVATE_SUBNET_CHANGE_EVENT),          /* ipacm_event_data_fid */
+	__stringify(IPA_FIREWALL_CHANGE_EVENT),                /* NULL */
+	__stringify(IPA_LINK_UP_EVENT),                        /* ipacm_event_data_fid */
+	__stringify(IPA_LINK_DOWN_EVENT),                      /* ipacm_event_data_fid */
+	__stringify(IPA_USB_LINK_UP_EVENT),                    /* ipacm_event_data_fid */
+	__stringify(IPA_BRIDGE_LINK_UP_EVENT),                 /* ipacm_event_data_all */
+	__stringify(IPA_WAN_EMBMS_LINK_UP_EVENT),              /* ipacm_event_data_mac */
+	__stringify(IPA_ADDR_ADD_EVENT),                       /* ipacm_event_data_addr */
+	__stringify(IPA_ADDR_DEL_EVENT),                       /* no use */
+	__stringify(IPA_ROUTE_ADD_EVENT),                      /* ipacm_event_data_addr */
+	__stringify(IPA_ROUTE_DEL_EVENT),                      /* ipacm_event_data_addr */
+	__stringify(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT),         /* ipacm_event_data_fid */
+	__stringify(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT),         /* ipacm_event_data_fid */
+	__stringify(IPA_WLAN_AP_LINK_UP_EVENT),                /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_STA_LINK_UP_EVENT),               /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_LINK_DOWN_EVENT),                 /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_CLIENT_ADD_EVENT),                /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_CLIENT_ADD_EVENT_EX),             /* ipacm_event_data_wlan_ex */
+	__stringify(IPA_WLAN_CLIENT_DEL_EVENT),                /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_CLIENT_POWER_SAVE_EVENT),         /* ipacm_event_data_mac */
+	__stringify(IPA_WLAN_CLIENT_RECOVER_EVENT),            /* ipacm_event_data_mac */
+	__stringify(IPA_NEW_NEIGH_EVENT),                      /* ipacm_event_data_all */
+	__stringify(IPA_DEL_NEIGH_EVENT),                      /* ipacm_event_data_all */
+	__stringify(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT),       /* ipacm_event_data_all */
+	__stringify(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT),       /* ipacm_event_data_all */
+	__stringify(IPA_SW_ROUTING_ENABLE),                    /* NULL */
+	__stringify(IPA_SW_ROUTING_DISABLE),                   /* NULL */
+	__stringify(IPA_PROCESS_CT_MESSAGE),                   /* ipacm_ct_evt_data */
+	__stringify(IPA_PROCESS_CT_MESSAGE_V6),                /* ipacm_ct_evt_data */
+	__stringify(IPA_LAN_TO_LAN_NEW_CONNECTION),            /* ipacm_event_connection */
+	__stringify(IPA_LAN_TO_LAN_DEL_CONNECTION),            /* ipacm_event_connection */
+	__stringify(IPA_WLAN_SWITCH_TO_SCC),                   /* No Data */
+	__stringify(IPA_WLAN_SWITCH_TO_MCC),                   /* No Data */
+	__stringify(IPA_CRADLE_WAN_MODE_SWITCH),               /* ipacm_event_cradle_wan_mode */
+	__stringify(IPA_WAN_XLAT_CONNECT_EVENT),               /* ipacm_event_data_fid */
+	__stringify(IPA_TETHERING_STATS_UPDATE_EVENT),         /* ipacm_event_data_fid */
+	__stringify(IPA_NETWORK_STATS_UPDATE_EVENT),           /* ipacm_event_data_fid */
+	__stringify(IPA_EXTERNAL_EVENT_MAX),
+	__stringify(IPA_HANDLE_WAN_UP),                        /* ipacm_event_iface_up  */
+	__stringify(IPA_HANDLE_WAN_DOWN),                      /* ipacm_event_iface_up  */
+	__stringify(IPA_HANDLE_WAN_UP_V6),                     /* NULL */
+	__stringify(IPA_HANDLE_WAN_DOWN_V6),                   /* NULL */
+	__stringify(IPA_HANDLE_WAN_UP_TETHER),                 /* ipacm_event_iface_up_tehter */
+	__stringify(IPA_HANDLE_WAN_DOWN_TETHER),               /* ipacm_event_iface_up_tehter */
+	__stringify(IPA_HANDLE_WAN_UP_V6_TETHER),              /* ipacm_event_iface_up_tehter */
+	__stringify(IPA_HANDLE_WAN_DOWN_V6_TETHER),            /* ipacm_event_iface_up_tehter */
+	__stringify(IPA_HANDLE_WLAN_UP),                       /* ipacm_event_iface_up */
+	__stringify(IPA_HANDLE_LAN_UP),                        /* ipacm_event_iface_up */
+	__stringify(IPA_ETH_BRIDGE_IFACE_UP),                  /* ipacm_event_eth_bridge*/
+	__stringify(IPA_ETH_BRIDGE_IFACE_DOWN),                /* ipacm_event_eth_bridge*/
+	__stringify(IPA_ETH_BRIDGE_CLIENT_ADD),                /* ipacm_event_eth_bridge*/
+	__stringify(IPA_ETH_BRIDGE_CLIENT_DEL),                /* ipacm_event_eth_bridge*/
+	__stringify(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH),       /* ipacm_event_eth_bridge*/
+	__stringify(IPA_LAN_DELETE_SELF),                      /* ipacm_event_data_fid */
+	__stringify(IPACM_EVENT_MAX),
+};
+
+IPACM_Config::IPACM_Config()
+{
+	iface_table = NULL;
+	alg_table = NULL;
+	pNatIfaces = NULL;
+	memset(&ipa_client_rm_map_tbl, 0, sizeof(ipa_client_rm_map_tbl));
+	memset(&ipa_rm_tbl, 0, sizeof(ipa_rm_tbl));
+	ipa_rm_a2_check=0;
+	ipacm_odu_enable = false;
+	ipacm_odu_router_mode = false;
+	ipa_num_wlan_guest_ap = 0;
+
+	ipa_num_ipa_interfaces = 0;
+	ipa_num_private_subnet = 0;
+	ipa_num_alg_ports = 0;
+	ipa_nat_max_entries = 0;
+	ipa_nat_iface_entries = 0;
+	ipa_sw_rt_enable = false;
+	ipa_bridge_enable = false;
+	isMCC_Mode = false;
+	ipa_max_valid_rm_entry = 0;
+
+	memset(&rt_tbl_default_v4, 0, sizeof(rt_tbl_default_v4));
+	memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
+	memset(&rt_tbl_wan_v4, 0, sizeof(rt_tbl_wan_v4));
+	memset(&rt_tbl_v6, 0, sizeof(rt_tbl_v6));
+	memset(&rt_tbl_wan_v6, 0, sizeof(rt_tbl_wan_v6));
+	memset(&rt_tbl_wan_dl, 0, sizeof(rt_tbl_wan_dl));
+	memset(&rt_tbl_odu_v4, 0, sizeof(rt_tbl_odu_v4));
+	memset(&rt_tbl_odu_v6, 0, sizeof(rt_tbl_odu_v6));
+
+	memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
+	memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
+
+	qmap_id = ~0;
+
+	memset(flt_rule_count_v4, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
+	memset(flt_rule_count_v6, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
+	memset(bridge_mac, 0, IPA_MAC_ADDR_SIZE*sizeof(uint8_t));
+
+	IPACMDBG_H(" create IPACM_Config constructor\n");
+	return;
+}
+
+int IPACM_Config::Init(void)
+{
+	/* Read IPACM Config file */
+	char	IPACM_config_file[IPA_MAX_FILE_LEN];
+	IPACM_conf_t	*cfg;
+	cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
+	if(cfg == NULL)
+	{
+		IPACMERR("Unable to allocate cfg memory.\n");
+		return IPACM_FAILURE;
+	}
+	uint32_t subnet_addr;
+	uint32_t subnet_mask;
+	int i, ret = IPACM_SUCCESS;
+	struct in_addr in_addr_print;
+
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (0 > m_fd)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+	}
+	strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+
+	IPACMDBG_H("\n IPACM XML file is %s \n", IPACM_config_file);
+	if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
+	{
+		IPACMDBG_H("\n IPACM XML read OK \n");
+	}
+	else
+	{
+		IPACMERR("\n IPACM XML read failed \n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+
+	/* Construct IPACM Iface table */
+	ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
+	if (iface_table != NULL)
+	{
+		free(iface_table);
+		iface_table = NULL;
+		IPACMDBG_H("RESET IPACM_Config::iface_table\n");
+	}
+	iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
+					sizeof(ipa_ifi_dev_name_t));
+	if(iface_table == NULL)
+	{
+		IPACMERR("Unable to allocate iface_table memory.\n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+
+	for (i = 0; i < cfg->iface_config.num_iface_entries; i++)
+	{
+		strncpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
+		iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
+		iface_table[i].if_mode = cfg->iface_config.iface_entries[i].if_mode;
+		iface_table[i].wlan_mode = cfg->iface_config.iface_entries[i].wlan_mode;
+		IPACMDBG_H("IPACM_Config::iface_table[%d] = %s, cat=%d, mode=%d wlan-mode=%d \n", i, iface_table[i].iface_name,
+				iface_table[i].if_cat, iface_table[i].if_mode, iface_table[i].wlan_mode);
+		/* copy bridge interface name to ipacmcfg */
+		if( iface_table[i].if_cat == VIRTUAL_IF)
+		{
+			strlcpy(ipa_virtual_iface_name, iface_table[i].iface_name, sizeof(ipa_virtual_iface_name));
+			IPACMDBG_H("ipa_virtual_iface_name(%s) \n", ipa_virtual_iface_name);
+		}
+	}
+
+	/* Construct IPACM Private_Subnet table */
+	memset(&private_subnet_table, 0, sizeof(private_subnet_table));
+	ipa_num_private_subnet = cfg->private_subnet_config.num_subnet_entries;
+
+	for (i = 0; i < cfg->private_subnet_config.num_subnet_entries; i++)
+	{
+		memcpy(&private_subnet_table[i].subnet_addr,
+					 &cfg->private_subnet_config.private_subnet_entries[i].subnet_addr,
+					 sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_addr));
+
+		memcpy(&private_subnet_table[i].subnet_mask,
+					 &cfg->private_subnet_config.private_subnet_entries[i].subnet_mask,
+					 sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_mask));
+
+		subnet_addr = htonl(private_subnet_table[i].subnet_addr);
+		memcpy(&in_addr_print,&subnet_addr,sizeof(in_addr_print));
+		IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
+						 inet_ntoa(in_addr_print));
+
+		subnet_mask =  htonl(private_subnet_table[i].subnet_mask);
+		memcpy(&in_addr_print,&subnet_mask,sizeof(in_addr_print));
+		IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
+						 inet_ntoa(in_addr_print));
+	}
+
+	/* Construct IPACM ALG table */
+	ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
+	if (alg_table != NULL)
+	{
+		free(alg_table);
+		alg_table = NULL;
+		IPACMDBG_H("RESET IPACM_Config::alg_table \n");
+	}
+	alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
+				sizeof(ipacm_alg));
+	if(alg_table == NULL)
+	{
+		IPACMERR("Unable to allocate alg_table memory.\n");
+		ret = IPACM_FAILURE;
+		free(iface_table);
+		goto fail;;
+	}
+	for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
+	{
+		alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
+		alg_table[i].port = cfg->alg_config.alg_entries[i].port;
+		IPACMDBG_H("IPACM_Config::ipacm_alg[%d] = %d, port=%d\n", i, alg_table[i].protocol, alg_table[i].port);
+	}
+
+	ipa_nat_max_entries = cfg->nat_max_entries;
+	IPACMDBG_H("Nat Maximum Entries %d\n", ipa_nat_max_entries);
+
+	/* Find ODU is either router mode or bridge mode*/
+	ipacm_odu_enable = cfg->odu_enable;
+	ipacm_odu_router_mode = cfg->router_mode_enable;
+	ipacm_odu_embms_enable = cfg->odu_embms_enable;
+	IPACMDBG_H("ipacm_odu_enable %d\n", ipacm_odu_enable);
+	IPACMDBG_H("ipacm_odu_mode %d\n", ipacm_odu_router_mode);
+	IPACMDBG_H("ipacm_odu_embms_enable %d\n", ipacm_odu_embms_enable);
+
+	ipacm_ip_passthrough_mode = cfg->ip_passthrough_mode;
+	IPACMDBG_H("ipacm_ip_passthrough_mode %d. \n", ipacm_ip_passthrough_mode);
+
+	ipa_num_wlan_guest_ap = cfg->num_wlan_guest_ap;
+	IPACMDBG_H("ipa_num_wlan_guest_ap %d\n",ipa_num_wlan_guest_ap);
+
+	/* Allocate more non-nat entries if the monitored iface dun have Tx/Rx properties */
+	if (pNatIfaces != NULL)
+	{
+		free(pNatIfaces);
+		pNatIfaces = NULL;
+		IPACMDBG_H("RESET IPACM_Config::pNatIfaces \n");
+	}
+	ipa_nat_iface_entries = 0;
+	pNatIfaces = (NatIfaces *)calloc(ipa_num_ipa_interfaces, sizeof(NatIfaces));
+	if (pNatIfaces == NULL)
+	{
+		IPACMERR("unable to allocate nat ifaces\n");
+		ret = IPACM_FAILURE;
+		free(iface_table);
+		free(alg_table);
+		goto fail;
+	}
+
+	/* Construct the routing table ictol name in iface static member*/
+	rt_tbl_default_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_default_v4.name, V4_DEFAULT_ROUTE_TABLE_NAME, sizeof(rt_tbl_default_v4.name));
+
+	rt_tbl_lan_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_lan_v4.name, V4_LAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_lan_v4.name));
+
+	rt_tbl_wan_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_wan_v4.name, V4_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v4.name));
+
+	rt_tbl_v6.ip = IPA_IP_v6;
+	strncpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.name));
+
+	rt_tbl_wan_v6.ip = IPA_IP_v6;
+	strncpy(rt_tbl_wan_v6.name, V6_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v6.name));
+
+	rt_tbl_odu_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_odu_v4.name, V4_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v4.name));
+
+	rt_tbl_odu_v6.ip = IPA_IP_v6;
+	strncpy(rt_tbl_odu_v6.name, V6_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v6.name));
+
+	rt_tbl_wan_dl.ip = IPA_IP_MAX;
+	strncpy(rt_tbl_wan_dl.name, WAN_DL_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_dl.name));
+
+	/* Construct IPACM ipa_client map to rm_resource table */
+	ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_PROD]= IPA_RM_RESOURCE_WLAN_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_USB_PROD]= IPA_RM_RESOURCE_USB_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_A5_WLAN_AMPDU_PROD]= IPA_RM_RESOURCE_HSIC_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_APPS_LAN_WAN_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_WLAN2_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_WLAN3_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_WLAN4_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_USB_CONS]= IPA_RM_RESOURCE_USB_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_APPS_WAN_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_PROD]= IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_EMB_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_TETH_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+
+	/* Create the entries which IPACM wants to add dependencies on */
+	ipa_rm_tbl[0].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+	ipa_rm_tbl[0].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+	ipa_rm_tbl[0].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+	ipa_rm_tbl[0].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+	ipa_rm_tbl[1].producer_rm1 = IPA_RM_RESOURCE_USB_PROD;
+	ipa_rm_tbl[1].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+	ipa_rm_tbl[1].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+	ipa_rm_tbl[1].consumer_rm2 = IPA_RM_RESOURCE_USB_CONS;
+
+	ipa_rm_tbl[2].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+	ipa_rm_tbl[2].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
+	ipa_rm_tbl[2].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
+	ipa_rm_tbl[2].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+	ipa_rm_tbl[3].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[3].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+	ipa_rm_tbl[3].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+	ipa_rm_tbl[3].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+
+	ipa_rm_tbl[4].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+	ipa_rm_tbl[4].consumer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_rm_tbl[4].producer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[4].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+	ipa_rm_tbl[5].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[5].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
+	ipa_rm_tbl[5].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
+	ipa_rm_tbl[5].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_max_valid_rm_entry = 6; /* max is IPA_MAX_RM_ENTRY (6)*/
+
+	IPACMDBG_H(" depend MAP-0 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_Q6_CONS);
+	IPACMDBG_H(" depend MAP-1 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_USB_PROD, IPA_RM_RESOURCE_Q6_CONS);
+	IPACMDBG_H(" depend MAP-2 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_USB_CONS);
+	IPACMDBG_H(" depend MAP-3 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS);
+	IPACMDBG_H(" depend MAP-4 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+	IPACMDBG_H(" depend MAP-5 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_USB_CONS);
+
+fail:
+	if (cfg != NULL)
+	{
+		free(cfg);
+		cfg = NULL;
+	}
+
+	return ret;
+}
+
+IPACM_Config* IPACM_Config::GetInstance()
+{
+	int res = IPACM_SUCCESS;
+
+	if (pInstance == NULL)
+	{
+		pInstance = new IPACM_Config();
+
+		res = pInstance->Init();
+		if (res != IPACM_SUCCESS)
+		{
+			delete pInstance;
+			IPACMERR("unable to initialize config instance\n");
+			return NULL;
+		}
+	}
+
+	return pInstance;
+}
+
+int IPACM_Config::GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts)
+{
+	if (nPorts <= 0 || pAlgPorts == NULL)
+	{
+		IPACMERR("Invalid input\n");
+		return -1;
+	}
+
+	for (int cnt = 0; cnt < nPorts; cnt++)
+	{
+		pAlgPorts[cnt].protocol = alg_table[cnt].protocol;
+		pAlgPorts[cnt].port = alg_table[cnt].port;
+	}
+
+	return 0;
+}
+
+int IPACM_Config::GetNatIfaces(int nIfaces, NatIfaces *pIfaces)
+{
+	if (nIfaces <= 0 || pIfaces == NULL)
+	{
+		IPACMERR("Invalid input\n");
+		return -1;
+	}
+
+	for (int cnt=0; cnt<nIfaces; cnt++)
+	{
+		memcpy(pIfaces[cnt].iface_name,
+					 pNatIfaces[cnt].iface_name,
+					 sizeof(pIfaces[cnt].iface_name));
+	}
+
+	return 0;
+}
+
+
+int IPACM_Config::AddNatIfaces(char *dev_name)
+{
+	int i;
+	/* Check if this iface already in NAT-iface*/
+	for(i = 0; i < ipa_nat_iface_entries; i++)
+	{
+		if(strncmp(dev_name,
+							 pNatIfaces[i].iface_name,
+							 sizeof(pNatIfaces[i].iface_name)) == 0)
+		{
+			IPACMDBG("Interface (%s) is add to nat iface already\n", dev_name);
+				return 0;
+		}
+	}
+
+	IPACMDBG_H("Add iface %s to NAT-ifaces, origin it has %d nat ifaces\n",
+					          dev_name, ipa_nat_iface_entries);
+	ipa_nat_iface_entries++;
+
+	if (ipa_nat_iface_entries < ipa_num_ipa_interfaces)
+	{
+		memcpy(pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
+					 dev_name, IPA_IFACE_NAME_LEN);
+
+		IPACMDBG_H("Add Nat IfaceName: %s ,update nat-ifaces number: %d\n",
+						 pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
+						 ipa_nat_iface_entries);
+	}
+
+	return 0;
+}
+
+int IPACM_Config::DelNatIfaces(char *dev_name)
+{
+	int i = 0;
+	IPACMDBG_H("Del iface %s from NAT-ifaces, origin it has %d nat ifaces\n",
+					 dev_name, ipa_nat_iface_entries);
+
+	for (i = 0; i < ipa_nat_iface_entries; i++)
+	{
+		if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
+		{
+			IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
+							 pNatIfaces[i].iface_name, ipa_nat_iface_entries);
+
+			/* Reset the matched entry */
+			memset(pNatIfaces[i].iface_name, 0, IPA_IFACE_NAME_LEN);
+
+			for (; i < ipa_nat_iface_entries - 1; i++)
+			{
+				memcpy(pNatIfaces[i].iface_name,
+							 pNatIfaces[i + 1].iface_name, IPA_IFACE_NAME_LEN);
+
+				/* Reset the copied entry */
+				memset(pNatIfaces[i + 1].iface_name, 0, IPA_IFACE_NAME_LEN);
+			}
+			ipa_nat_iface_entries--;
+			IPACMDBG_H("Update nat-ifaces number: %d\n", ipa_nat_iface_entries);
+			return 0;
+		}
+	}
+
+	IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
+					    dev_name, ipa_nat_iface_entries);
+	return 0;
+}
+
+/* for IPACM resource manager dependency usage
+   add either Tx or Rx ipa_rm_resource_name and
+   also indicate that endpoint property if valid */
+void IPACM_Config::AddRmDepend(ipa_rm_resource_name rm1,bool rx_bypass_ipa)
+{
+	int retval = 0;
+	struct ipa_ioc_rm_dependency dep;
+
+	IPACMDBG_H(" Got rm add-depend index : %d \n", rm1);
+	/* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
+	if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
+	{
+		ipa_rm_a2_check+=1;
+		IPACMDBG_H("got %d times default RT routing from A2 \n", ipa_rm_a2_check);
+	}
+
+	for(int i=0;i<ipa_max_valid_rm_entry;i++)
+	{
+		if(rm1 == ipa_rm_tbl[i].producer_rm1)
+		{
+			ipa_rm_tbl[i].producer1_up = true;
+			/* entry1's producer actually dun have registered Rx-property */
+			ipa_rm_tbl[i].rx_bypass_ipa = rx_bypass_ipa;
+			IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 with non_rx_prop: %d \n", i,ipa_rm_tbl[i].rx_bypass_ipa);
+
+			if(ipa_rm_tbl[i].consumer1_up == true && ipa_rm_tbl[i].rm_set == false)
+			{
+				IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency  \n", i);
+				/* add bi-directional dependency*/
+				if(ipa_rm_tbl[i].rx_bypass_ipa)
+				{
+					IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+				}
+				else
+				{
+					memset(&dep, 0, sizeof(dep));
+					dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+					dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+					retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+					IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+					if (retval)
+					{
+						IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+					}
+				}
+				memset(&dep, 0, sizeof(dep));
+				dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+				dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+				retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+				IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+				if (retval)
+				{
+					IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d)  \n", i,retval);
+				}
+				ipa_rm_tbl[i].rm_set = true;
+			}
+			else
+			{
+				IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
+			}
+		}
+
+		if(rm1 == ipa_rm_tbl[i].consumer_rm1)
+		{
+			ipa_rm_tbl[i].consumer1_up = true;
+			IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 \n", i);
+
+			if(ipa_rm_tbl[i].producer1_up == true && ipa_rm_tbl[i].rm_set == false)
+			{
+				IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency  \n", i);
+				/* add bi-directional dependency*/
+				if(ipa_rm_tbl[i].rx_bypass_ipa)
+				{
+					IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+				}
+				else
+				{
+					memset(&dep, 0, sizeof(dep));
+					dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+					dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+					retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+					IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+					if (retval)
+					{
+						IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d)  \n", i,retval);
+					}
+				}
+
+				memset(&dep, 0, sizeof(dep));
+				dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+				dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+				retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+				IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+				if (retval)
+				{
+					IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d)  \n", i,retval);
+				}
+				ipa_rm_tbl[i].rm_set = true;
+			}
+			else
+			{
+				IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
+			}
+	   }
+   }
+   return ;
+}
+
+/* for IPACM resource manager dependency usage
+   delete either Tx or Rx ipa_rm_resource_name */
+
+void IPACM_Config::DelRmDepend(ipa_rm_resource_name rm1)
+{
+	int retval = 0;
+	struct ipa_ioc_rm_dependency dep;
+
+	IPACMDBG_H(" Got rm del-depend index : %d \n", rm1);
+	/* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
+	if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
+	{
+		ipa_rm_a2_check-=1;
+		IPACMDBG_H("Left %d times default RT routing from A2 \n", ipa_rm_a2_check);
+	}
+
+	for(int i=0;i<ipa_max_valid_rm_entry;i++)
+	{
+
+		if(rm1 == ipa_rm_tbl[i].producer_rm1)
+		{
+			if(ipa_rm_tbl[i].rm_set == true)
+			{
+				IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 and dependency is up \n", i);
+				ipa_rm_tbl[i].rm_set = false;
+
+				/* delete bi-directional dependency*/
+				if(ipa_rm_tbl[i].rx_bypass_ipa)
+				{
+					IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+				}
+				else
+				{
+					memset(&dep, 0, sizeof(dep));
+					dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+					dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+					retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+					IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+					if (retval)
+					{
+						IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+					}
+				}
+				memset(&dep, 0, sizeof(dep));
+				dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+				dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+				retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+				IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+				if (retval)
+				{
+					IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+				}
+			}
+			ipa_rm_tbl[i].producer1_up = false;
+			ipa_rm_tbl[i].rx_bypass_ipa = false;
+		}
+		if(rm1 == ipa_rm_tbl[i].consumer_rm1)
+		{
+			/* ipa_rm_a2_check: IPA_RM_RESOURCE_!6_CONS*/
+			if(ipa_rm_tbl[i].consumer_rm1 == IPA_RM_RESOURCE_Q6_CONS && ipa_rm_a2_check == 1)
+			{
+				IPACMDBG_H(" still have %d default RT routing from A2 \n", ipa_rm_a2_check);
+				continue;
+			}
+
+			if(ipa_rm_tbl[i].rm_set == true)
+			{
+				IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 and dependency is up \n", i);
+				ipa_rm_tbl[i].rm_set = false;
+				/* delete bi-directional dependency*/
+				if(ipa_rm_tbl[i].rx_bypass_ipa)
+				{
+					IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+				}
+				else
+				{
+					memset(&dep, 0, sizeof(dep));
+					dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+					dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+					retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+					IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+					if (retval)
+					{
+						IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+					}
+				}
+
+				memset(&dep, 0, sizeof(dep));
+				dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+				dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+				retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+				IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+				if (retval)
+				{
+					IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+				}
+			}
+			ipa_rm_tbl[i].consumer1_up = false;
+		}
+	}
+	return ;
+}
+
+int IPACM_Config::SetExtProp(ipa_ioc_query_intf_ext_props *prop)
+{
+	int i, num;
+
+	if(prop == NULL || prop->num_ext_props <= 0)
+	{
+		IPACMERR("There is no extended property!\n");
+		return IPACM_FAILURE;
+	}
+
+	num = prop->num_ext_props;
+	for(i=0; i<num; i++)
+	{
+		if(prop->ext[i].ip == IPA_IP_v4)
+		{
+			if(ext_prop_v4.num_ext_props >= MAX_NUM_EXT_PROPS)
+			{
+				IPACMERR("IPv4 extended property table is full!\n");
+				continue;
+			}
+			memcpy(&ext_prop_v4.prop[ext_prop_v4.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
+			ext_prop_v4.num_ext_props++;
+		}
+		else if(prop->ext[i].ip == IPA_IP_v6)
+		{
+			if(ext_prop_v6.num_ext_props >= MAX_NUM_EXT_PROPS)
+			{
+				IPACMERR("IPv6 extended property table is full!\n");
+				continue;
+			}
+			memcpy(&ext_prop_v6.prop[ext_prop_v6.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
+			ext_prop_v6.num_ext_props++;
+		}
+		else
+		{
+			IPACMERR("The IP type is not expected!\n");
+			return IPACM_FAILURE;
+		}
+	}
+
+	IPACMDBG_H("Set extended property succeeded.\n");
+
+	return IPACM_SUCCESS;
+}
+
+ipacm_ext_prop* IPACM_Config::GetExtProp(ipa_ip_type ip_type)
+{
+	if(ip_type == IPA_IP_v4)
+		return &ext_prop_v4;
+	else if(ip_type == IPA_IP_v6)
+		return &ext_prop_v6;
+	else
+	{
+		IPACMERR("Failed to get extended property: the IP version is neither IPv4 nor IPv6!\n");
+		return NULL;
+	}
+}
+
+int IPACM_Config::DelExtProp(ipa_ip_type ip_type)
+{
+	if(ip_type != IPA_IP_v6)
+	{
+		memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
+	}
+
+	if(ip_type != IPA_IP_v4)
+	{
+		memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
+	}
+
+	return IPACM_SUCCESS;
+}
+
+const char* IPACM_Config::getEventName(ipa_cm_event_id event_id)
+{
+	if(event_id >= sizeof(ipacm_event_name)/sizeof(ipacm_event_name[0]))
+	{
+		IPACMERR("Event name array is not consistent with event array!\n");
+		return NULL;
+	}
+
+	return ipacm_event_name[event_id];
+}
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
new file mode 100644
index 0000000..146cedb
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -0,0 +1,652 @@
+/*
+Copyright (c) 2013-2016, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include "IPACM_Iface.h"
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Log.h"
+
+#define LO_NAME "lo"
+
+extern IPACM_EvtDispatcher cm_dis;
+extern void ParseCTMessage(struct nf_conntrack *ct);
+
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *CtList = NULL;
+
+/* ================================
+		 Local Function Definitions
+		 =================================
+*/
+IPACM_ConntrackClient::IPACM_ConntrackClient()
+{
+	IPACMDBG("\n");
+
+	tcp_hdl = NULL;
+	udp_hdl = NULL;
+	tcp_filter = NULL;
+	udp_filter = NULL;
+}
+
+IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
+{
+	if(pInstance == NULL)
+	{
+		pInstance = new IPACM_ConntrackClient();
+
+		pInstance->udp_filter = nfct_filter_create();
+		if(pInstance->udp_filter == NULL)
+		{
+			IPACMERR("unable to create UDP filter\n");
+			delete pInstance;
+			return NULL;
+		}
+		IPACMDBG("Created UDP filter\n");
+
+		pInstance->tcp_filter = nfct_filter_create();
+		if(pInstance->tcp_filter == NULL)
+		{
+			IPACMERR("unable to create TCP filter\n");
+			delete pInstance;
+			return NULL;
+		}
+		IPACMDBG("Created TCP filter\n");
+	}
+
+	return pInstance;
+}
+
+int IPACM_ConntrackClient::IPAConntrackEventCB
+(
+	 enum nf_conntrack_msg_type type,
+	 struct nf_conntrack *ct,
+	 void *data
+	 )
+{
+	ipacm_cmd_q_data evt_data;
+	ipacm_ct_evt_data *ct_data;
+	uint8_t ip_type = 0;
+
+	IPACMDBG("Event callback called with msgtype: %d\n",type);
+
+	/* Retrieve ip type */
+	ip_type = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
+
+#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;
+	ct_data->type = type;
+
+	evt_data.event = IPA_PROCESS_CT_MESSAGE;
+	evt_data.evt_data = (void *)ct_data;
+
+#ifdef CT_OPT
+	if(AF_INET6 == ip_type)
+	{
+		evt_data.event = IPA_PROCESS_CT_MESSAGE_V6;
+	}
+#endif
+
+	if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
+	{
+		IPACMERR("Error sending Conntrack message to processing thread!\n");
+		free(ct_data);
+		goto IGNORE;
+	}
+
+/* NFCT_CB_STOLEN means that the conntrack object is not released after the
+	 callback That must be manually done later when the object is no longer needed. */
+	return NFCT_CB_STOLEN;
+
+IGNORE:
+	nfct_destroy(ct);
+	return NFCT_CB_STOLEN;
+
+}
+
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Bridge_Addrs
+(
+	 struct nfct_filter *filter
+)
+{
+	int fd;
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if(fd < 0)
+	{
+		PERROR("unable to open socket");
+		return -1;
+	}
+
+	int ret;
+	uint32_t ipv4_addr;
+	struct ifreq ifr;
+
+	/* retrieve bridge interface ipv4 address */
+	memset(&ifr, 0, sizeof(struct ifreq));
+	ifr.ifr_addr.sa_family = AF_INET;
+	(void)strncpy(ifr.ifr_name, IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, sizeof(ifr.ifr_name));
+	IPACMDBG("bridge interface name (%s)\n", ifr.ifr_name);
+
+	ret = ioctl(fd, SIOCGIFADDR, &ifr);
+	if (ret < 0)
+	{
+		IPACMERR("unable to retrieve (%s) interface address\n",ifr.ifr_name);
+		close(fd);
+		return -1;
+	}
+	IPACMDBG("Interface (%s) address %s\n", ifr.ifr_name, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
+	ipv4_addr = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
+	close(fd);
+
+	/* ignore whatever is destined to or originates from broadcast ip address */
+	struct nfct_filter_ipv4 filter_ipv4;
+
+	filter_ipv4.addr = ipv4_addr;
+	filter_ipv4.mask = 0xffffffff;
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_SRC_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+  return 0;
+}
+
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Iface
+(
+	 struct nfct_filter *filter,
+	 ipacm_event_iface_up *param
+)
+{
+	struct nfct_filter_ipv4 filter_ipv4;
+
+	filter_ipv4.addr = param->ipv4_addr;
+	filter_ipv4.mask = 0xffffffff;
+
+	/* ignore whatever is destined to local interfaces */
+	IPACMDBG("Ignore connections destinated to interface %s", param->ifname);
+	iptodot("with ipv4 address", param->ipv4_addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	IPACMDBG("Ignore connections orignated from interface %s", param->ifname);
+	iptodot("with ipv4 address", filter_ipv4.addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_SRC_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+	/* Retrieve broadcast address */
+	/* Intialize with 255.255.255.255 */
+	uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+	/* calculate broadcast address from addr and addr_mask */
+	bc_ip_addr = (bc_ip_addr & (~param->addr_mask));
+	bc_ip_addr = (bc_ip_addr | (param->ipv4_addr & param->addr_mask));
+
+	/* netfitler expecting in host-byte order */
+	filter_ipv4.addr = bc_ip_addr;
+	filter_ipv4.mask = 0xffffffff;
+
+	iptodot("with broadcast address", filter_ipv4.addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	return 0;
+}
+
+/* Function which sets up filters to ignore
+		 connections to and from local interfaces */
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
+(
+	 struct nfct_filter *filter
+)
+{
+	struct nfct_filter_ipv4 filter_ipv4;
+
+	/* ignore whatever is destined to or originates from broadcast ip address */
+	filter_ipv4.addr = 0xffffffff;
+	filter_ipv4.mask = 0xffffffff;
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_SRC_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+	return 0;
+} /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
+
+/* Initialize TCP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_TCP_Filter_Init(void)
+{
+	int ret = 0;
+	IPACM_ConntrackClient *pClient;
+
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to get conntrack client instance\n");
+		return -1;
+	}
+
+	ret = nfct_filter_set_logic(pClient->tcp_filter,
+															NFCT_FILTER_L4PROTO,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("Unable to set filter logic\n");
+		return -1;
+	}
+
+	/* set protocol filters as tcp and udp */
+	nfct_filter_add_attr_u32(pClient->tcp_filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
+
+
+	struct nfct_filter_proto tcp_proto_state;
+	tcp_proto_state.proto = IPPROTO_TCP;
+	tcp_proto_state.state = TCP_CONNTRACK_ESTABLISHED;
+
+	ret = nfct_filter_set_logic(pClient->tcp_filter,
+															NFCT_FILTER_L4PROTO_STATE,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+		return -1;
+	}
+	nfct_filter_add_attr(pClient->tcp_filter,
+											 NFCT_FILTER_L4PROTO_STATE,
+											 &tcp_proto_state);
+
+
+	tcp_proto_state.proto = IPPROTO_TCP;
+	tcp_proto_state.state = TCP_CONNTRACK_FIN_WAIT;
+	ret = nfct_filter_set_logic(pClient->tcp_filter,
+															NFCT_FILTER_L4PROTO_STATE,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+		return -1;
+	}
+
+	nfct_filter_add_attr(pClient->tcp_filter,
+											 NFCT_FILTER_L4PROTO_STATE,
+											 &tcp_proto_state);
+	return 0;
+}
+
+
+/* Initialize UDP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_UDP_Filter_Init(void)
+{
+	int ret = 0;
+	IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to get conntrack client instance\n");
+		return -1;
+	}
+
+	ret = nfct_filter_set_logic(pClient->udp_filter,
+															NFCT_FILTER_L4PROTO,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+	}
+	/* set protocol filters as tcp and udp */
+	nfct_filter_add_attr_u32(pClient->udp_filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
+
+	return 0;
+}
+
+void* IPACM_ConntrackClient::UDPConnTimeoutUpdate(void *ptr)
+{
+
+	NatApp *nat_inst = NULL;
+#ifdef IPACM_DEBUG
+	IPACMDBG("\n");
+#endif
+
+	nat_inst = NatApp::GetInstance();
+	if(nat_inst == NULL)
+	{
+		IPACMERR("unable to create nat instance\n");
+		return NULL;
+	}
+
+	while(1)
+	{
+		nat_inst->UpdateUDPTimeStamp();
+		sleep(UDP_TIMEOUT_UPDATE);
+	} /* end of while(1) loop */
+
+#ifdef IPACM_DEBUG
+	IPACMDBG("Returning from %s() %d\n", __FUNCTION__, __LINE__);
+#endif
+
+	return NULL;
+}
+
+/* Thread to initialize TCP Conntrack Filters*/
+void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *)
+{
+	int ret;
+	IPACM_ConntrackClient *pClient;
+	unsigned subscrips = 0;
+
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to get conntrack client instance\n");
+		return NULL;
+	}
+
+	subscrips = (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
+#ifdef CT_OPT
+	subscrips |= NF_NETLINK_CONNTRACK_NEW;
+#endif
+
+	pClient->tcp_hdl = nfct_open(CONNTRACK, subscrips);
+	if(pClient->tcp_hdl == NULL)
+	{
+		PERROR("nfct_open\n");
+		return NULL;
+	}
+
+	/* Initialize the filter */
+	ret = IPA_Conntrack_TCP_Filter_Init();
+	if(ret == -1)
+	{
+		IPACMERR("Unable to initliaze TCP Filter\n");
+		return NULL;
+	}
+
+	/* Attach the filter to net filter handler */
+	ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+	if(ret == -1)
+	{
+		IPACMDBG("unable to attach TCP filter\n");
+		return NULL;
+	}
+
+	/* Register callback with netfilter handler */
+	IPACMDBG_H("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+#ifndef CT_OPT
+	nfct_callback_register(pClient->tcp_hdl,
+			(nf_conntrack_msg_type)	(NFCT_T_UPDATE | NFCT_T_DESTROY | NFCT_T_NEW),
+						IPAConntrackEventCB, NULL);
+#else
+	nfct_callback_register(pClient->tcp_hdl, (nf_conntrack_msg_type) NFCT_T_ALL, IPAConntrackEventCB, NULL);
+#endif
+
+	/* Block to catch events from net filter connection track */
+	/* nfct_catch() receives conntrack events from kernel-space, by default it
+			 blocks waiting for events. */
+	IPACMDBG("Waiting for events\n");
+
+	ret = nfct_catch(pClient->tcp_hdl);
+	if(ret == -1)
+	{
+		IPACMERR("(%d)(%s)\n", ret, strerror(errno));
+		return NULL;
+	}
+
+	IPACMDBG("Exit from tcp thread\n");
+
+	/* destroy the filter.. this will not detach the filter */
+	nfct_filter_destroy(pClient->tcp_filter);
+	pClient->tcp_filter = NULL;
+
+	/* de-register the callback */
+	nfct_callback_unregister(pClient->tcp_hdl);
+	/* close the handle */
+	nfct_close(pClient->tcp_hdl);
+	pClient->tcp_hdl = NULL;
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+/* Thread to initialize UDP Conntrack Filters*/
+void* IPACM_ConntrackClient::UDPRegisterWithConnTrack(void *)
+{
+	int ret;
+	IPACM_ConntrackClient *pClient = NULL;
+
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to retrieve instance of conntrack client\n");
+		return NULL;
+	}
+
+	pClient->udp_hdl = nfct_open(CONNTRACK,
+					(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
+	if(pClient->udp_hdl == NULL)
+	{
+		PERROR("nfct_open\n");
+		return NULL;
+	}
+
+	/* Initialize Filter */
+	ret = IPA_Conntrack_UDP_Filter_Init();
+	if(-1 == ret)
+	{
+		IPACMDBG("Unable to initalize udp filters\n");
+		return NULL;
+	}
+
+	/* Attach the filter to net filter handler */
+	ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+	if(ret == -1)
+	{
+		IPACMDBG("unable to attach the filter\n");
+		return NULL;
+	}
+
+	/* Register callback with netfilter handler */
+	IPACMDBG_H("udp handle:%p, fd:%d\n", pClient->udp_hdl, nfct_fd(pClient->udp_hdl));
+	nfct_callback_register(pClient->udp_hdl,
+			(nf_conntrack_msg_type)(NFCT_T_NEW | NFCT_T_DESTROY),
+			IPAConntrackEventCB,
+			NULL);
+
+	/* Block to catch events from net filter connection track */
+ctcatch:
+	ret = nfct_catch(pClient->udp_hdl);
+	if(ret == -1)
+	{
+		IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
+		return NULL;
+	}
+	else
+	{
+		IPACMDBG("ctcatch ret:%d\n", ret);
+		goto ctcatch;
+	}
+
+	IPACMDBG("Exit from udp thread with ret: %d\n", ret);
+
+	/* destroy the filter.. this will not detach the filter */
+	nfct_filter_destroy(pClient->udp_filter);
+	pClient->udp_filter = NULL;
+
+	/* de-register the callback */
+	nfct_callback_unregister(pClient->udp_hdl);
+	/* close the handle */
+	nfct_close(pClient->udp_hdl);
+	pClient->udp_hdl = NULL;
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+void IPACM_ConntrackClient::UpdateUDPFilters(void *param, bool isWan)
+{
+	static bool isIgnore = false;
+	int ret = 0;
+	IPACM_ConntrackClient *pClient = NULL;
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to retrieve conntrack client instance\n");
+		return;
+	}
+
+	if(pClient->udp_filter == NULL)
+	{
+		 return;
+	}
+
+	if(!isWan)
+	{
+		IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->udp_filter,
+																		 (ipacm_event_iface_up *)param);
+
+		if(!isIgnore)
+		{
+			IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+			IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+			isIgnore = true;
+		}
+	}
+
+	/* Attach the filter to udp handle */
+	if(pClient->udp_hdl != NULL)
+	{
+		IPACMDBG("attaching the filter to udp handle\n");
+		ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+		if(ret == -1)
+		{
+			PERROR("unable to attach the filter to udp handle\n");
+			IPACMERR("udp handle:%p, fd:%d Error: %d\n",pClient->udp_hdl, nfct_fd(pClient->udp_hdl), ret);
+			return;
+		}
+	}
+
+	return;
+}
+
+void IPACM_ConntrackClient::UpdateTCPFilters(void *param, bool isWan)
+{
+	static bool isIgnore = false;
+	int ret = 0;
+	IPACM_ConntrackClient *pClient = NULL;
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to retrieve conntrack client instance\n");
+		return;
+	}
+
+	if(pClient->tcp_filter == NULL)
+		return;
+
+	if(!isWan)
+	{
+		IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->tcp_filter,
+																	(ipacm_event_iface_up *)param);
+
+		if(!isIgnore)
+		{
+			IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+			IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+			isIgnore = true;
+		}
+	}
+
+	/* Attach the filter to tcp handle */
+	if(pClient->tcp_hdl != NULL)
+	{
+		IPACMDBG("attaching the filter to tcp handle\n");
+		ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+		if(ret == -1)
+		{
+			PERROR("unable to attach the filter to tcp handle\n");
+			IPACMERR("tcp handle:%p, fd:%d Error: %d\n",pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl), ret);
+			return;
+		}
+	}
+
+  return;
+}
+
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
new file mode 100644
index 0000000..38ab7da
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -0,0 +1,1200 @@
+/*
+Copyright (c) 2013-2016, 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 <sys/ioctl.h>
+#include <net/if.h>
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Wan.h"
+
+IPACM_ConntrackListener::IPACM_ConntrackListener()
+{
+	 IPACMDBG("\n");
+
+	 isNatThreadStart = false;
+	 isCTReg = false;
+	 WanUp = false;
+	 nat_inst = NatApp::GetInstance();
+
+	 NatIfaceCnt = 0;
+	 StaClntCnt = 0;
+	 pNatIfaces = NULL;
+	 pConfig = IPACM_Config::GetInstance();;
+
+	 memset(nat_iface_ipv4_addr, 0, sizeof(nat_iface_ipv4_addr));
+	 memset(nonnat_iface_ipv4_addr, 0, sizeof(nonnat_iface_ipv4_addr));
+	 memset(sta_clnt_ipv4_addr, 0, sizeof(sta_clnt_ipv4_addr));
+
+	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, this);
+	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, this);
+	 IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE, this);
+	 IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE_V6, this);
+	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
+	 IPACM_EvtDispatcher::registr(IPA_HANDLE_LAN_UP, this);
+	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, this);
+	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, this);
+
+#ifdef CT_OPT
+	 p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
+#endif
+}
+
+void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
+						void *data)
+{
+	 ipacm_event_iface_up *wan_down = NULL;
+
+	 if(data == NULL)
+	 {
+		 IPACMERR("Invalid Data\n");
+		 return;
+	 }
+
+	 switch(evt)
+	 {
+	 case IPA_PROCESS_CT_MESSAGE:
+			IPACMDBG("Received IPA_PROCESS_CT_MESSAGE event\n");
+			ProcessCTMessage(data);
+			break;
+
+#ifdef CT_OPT
+	 case IPA_PROCESS_CT_MESSAGE_V6:
+			IPACMDBG("Received IPA_PROCESS_CT_MESSAGE_V6 event\n");
+			ProcessCTV6Message(data);
+			break;
+#endif
+
+	 case IPA_HANDLE_WAN_UP:
+			IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+			CreateConnTrackThreads();
+			if(!isWanUp())
+			{
+				TriggerWANUp(data);
+			}
+			break;
+
+	 case IPA_HANDLE_WAN_DOWN:
+			IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+			wan_down = (ipacm_event_iface_up *)data;
+			if(isWanUp())
+			{
+				TriggerWANDown(wan_down->ipv4_addr);
+			}
+			break;
+
+	/* if wlan or lan comes up after wan interface, modify
+		 tcp/udp filters to ignore local wlan or lan connections */
+	 case IPA_HANDLE_WLAN_UP:
+	 case IPA_HANDLE_LAN_UP:
+			IPACMDBG_H("Received event: %d with ifname: %s and address: 0x%x\n",
+							 evt, ((ipacm_event_iface_up *)data)->ifname,
+							 ((ipacm_event_iface_up *)data)->ipv4_addr);
+			CreateConnTrackThreads();
+			IPACM_ConntrackClient::UpdateUDPFilters(data, false);
+			IPACM_ConntrackClient::UpdateTCPFilters(data, false);
+			break;
+
+	 case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		 IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT event\n");
+		 HandleNonNatIPAddr(data, true);
+		 break;
+
+	 case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+		 IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT event\n");
+		 HandleNonNatIPAddr(data, false);
+		 break;
+
+	 default:
+			IPACMDBG("Ignore cmd %d\n", evt);
+			break;
+	 }
+}
+
+int IPACM_ConntrackListener::CheckNatIface(
+   ipacm_event_data_all *data, bool *NatIface)
+{
+	int fd = 0, len = 0, cnt, i, j;
+	struct ifreq ifr;
+	*NatIface = false;
+
+	if (data->ipv4_addr == 0 || data->iptype != IPA_IP_v4)
+	{
+		IPACMDBG("Ignoring\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG("Received interface index %d with ip type: %d", data->if_index, data->iptype);
+	iptodot(" and ipv4 address", data->ipv4_addr);
+
+	if (pConfig == NULL)
+	{
+		pConfig = IPACM_Config::GetInstance();
+		if (pConfig == NULL)
+		{
+			IPACMERR("Unable to get Config instance\n");
+			return IPACM_FAILURE;
+		}
+	}
+
+	cnt = pConfig->GetNatIfacesCnt();
+	NatIfaceCnt = cnt;
+	IPACMDBG("Total Nat ifaces: %d\n", NatIfaceCnt);
+	if (pNatIfaces != NULL)
+	{
+		free(pNatIfaces);
+		pNatIfaces = NULL;
+	}
+
+	len = (sizeof(NatIfaces) * NatIfaceCnt);
+	pNatIfaces = (NatIfaces *)malloc(len);
+	if (pNatIfaces == NULL)
+	{
+		IPACMERR("Unable to allocate memory for non nat ifaces\n");
+		return IPACM_FAILURE;
+	}
+
+	memset(pNatIfaces, 0, len);
+	if (pConfig->GetNatIfaces(NatIfaceCnt, pNatIfaces) != 0)
+	{
+		IPACMERR("Unable to retrieve non nat ifaces\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Search/Configure linux interface-index and map it to IPA interface-index */
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface name socket create failed");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+	ifr.ifr_ifindex = data->if_index;
+	if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		PERROR("call_ioctl_on_dev: ioctl failed:");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+	close(fd);
+
+	for (i = 0; i < NatIfaceCnt; i++)
+	{
+		if (strncmp(ifr.ifr_name,
+					pNatIfaces[i].iface_name,
+					sizeof(pNatIfaces[i].iface_name)) == 0)
+		{
+			IPACMDBG_H("Nat iface (%s), entry (%d), dont cache",
+						pNatIfaces[i].iface_name, j);
+			iptodot("with ipv4 address: ", nat_iface_ipv4_addr[j]);
+			*NatIface = true;
+			return IPACM_SUCCESS;
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+void IPACM_ConntrackListener::HandleNonNatIPAddr(
+   void *inParam, bool AddOp)
+{
+	ipacm_event_data_all *data = (ipacm_event_data_all *)inParam;
+	bool NatIface = false;
+	int cnt, ret;
+
+	if (isStaMode)
+	{
+		IPACMDBG("In STA mode, don't add dummy rules for non nat ifaces\n");
+		return;
+	}
+
+	/* Handle only non nat ifaces, NAT iface should be handle
+	   separately to avoid race conditions between route/nat
+	   rules add/delete operations */
+	if (AddOp)
+	{
+		ret = CheckNatIface(data, &NatIface);
+		if (!NatIface && ret == IPACM_SUCCESS)
+		{
+			/* Cache the non nat iface ip address */
+			for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+			{
+				if (nonnat_iface_ipv4_addr[cnt] == 0)
+				{
+					nonnat_iface_ipv4_addr[cnt] = data->ipv4_addr;
+					IPACMDBG("Add ip addr to non nat list (%d) ", cnt);
+					iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+
+					/* Add dummy nat rule for non nat ifaces */
+					nat_inst->FlushTempEntries(data->ipv4_addr, true, true);
+					return;
+				}
+			}
+		}
+	}
+	else
+	{
+		/* for delete operation */
+		for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+		{
+			if (nonnat_iface_ipv4_addr[cnt] == data->ipv4_addr)
+			{
+				IPACMDBG("Reseting ct filters, entry (%d) ", cnt);
+				iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+				nonnat_iface_ipv4_addr[cnt] = 0;
+				nat_inst->FlushTempEntries(data->ipv4_addr, false);
+				nat_inst->DelEntriesOnClntDiscon(data->ipv4_addr);
+				return;
+			}
+		}
+
+	}
+
+	return;
+}
+
+void IPACM_ConntrackListener::HandleNeighIpAddrAddEvt(
+   ipacm_event_data_all *data)
+{
+	bool NatIface = false;
+	int j, ret;
+
+	ret = CheckNatIface(data, &NatIface);
+	if (NatIface && ret == IPACM_SUCCESS)
+	{
+		for (j = 0; j < MAX_IFACE_ADDRESS; j++)
+		{
+			/* check if duplicate NAT ip */
+			if (nat_iface_ipv4_addr[j] == data->ipv4_addr)
+				break;
+
+			/* Cache the new nat iface address */
+			if (nat_iface_ipv4_addr[j] == 0)
+			{
+				nat_iface_ipv4_addr[j] = data->ipv4_addr;
+				iptodot("Nating connections of addr: ", nat_iface_ipv4_addr[j]);
+				break;
+			}
+		}
+
+		/* Add the cached temp entries to NAT table */
+		if (j != MAX_IFACE_ADDRESS)
+		{
+			nat_inst->ResetPwrSaveIf(data->ipv4_addr);
+			nat_inst->FlushTempEntries(data->ipv4_addr, true);
+		}
+	}
+	return;
+}
+
+void IPACM_ConntrackListener::HandleNeighIpAddrDelEvt(
+   uint32_t ipv4_addr)
+{
+	int cnt;
+
+	if(ipv4_addr == 0)
+	{
+		IPACMDBG("Ignoring\n");
+		return;
+	}
+
+	iptodot("HandleNeighIpAddrDelEvt(): Received ip addr", ipv4_addr);
+	for(cnt = 0; cnt<MAX_IFACE_ADDRESS; cnt++)
+	{
+		if (nat_iface_ipv4_addr[cnt] == ipv4_addr)
+		{
+			IPACMDBG("Reseting ct nat iface, entry (%d) ", cnt);
+			iptodot("with ipv4 address", nat_iface_ipv4_addr[cnt]);
+			nat_iface_ipv4_addr[cnt] = 0;
+			nat_inst->FlushTempEntries(ipv4_addr, false);
+			nat_inst->DelEntriesOnClntDiscon(ipv4_addr);
+		}
+	}
+
+	return;
+}
+
+void IPACM_ConntrackListener::TriggerWANUp(void *in_param)
+{
+	 ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
+
+	 IPACMDBG_H("Recevied below information during wanup,\n");
+	 IPACMDBG_H("if_name:%s, ipv4_address:0x%x\n",
+						wanup_data->ifname, wanup_data->ipv4_addr);
+
+	 if(wanup_data->ipv4_addr == 0)
+	 {
+		 IPACMERR("Invalid ipv4 address,ignoring IPA_HANDLE_WAN_UP event\n");
+		 return;
+	 }
+
+	 WanUp = true;
+	 isStaMode = wanup_data->is_sta;
+	 IPACMDBG("isStaMode: %d\n", isStaMode);
+
+	 wan_ipaddr = wanup_data->ipv4_addr;
+	 memcpy(wan_ifname, wanup_data->ifname, sizeof(wan_ifname));
+
+	 if(nat_inst != NULL)
+	 {
+		 nat_inst->AddTable(wanup_data->ipv4_addr);
+	 }
+
+	 IPACMDBG("creating nat threads\n");
+	 CreateNatThreads();
+}
+
+int IPACM_ConntrackListener::CreateConnTrackThreads(void)
+{
+	int ret;
+	pthread_t tcp_thread = 0, udp_thread = 0;
+
+	if(isCTReg == false)
+	{
+		if(!tcp_thread)
+		{
+			ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+			if(0 != ret)
+			{
+				IPACMERR("unable to create TCP conntrack event listner thread\n");
+				PERROR("unable to create TCP conntrack\n");
+				return -1;
+			}
+
+			IPACMDBG("created TCP conntrack event listner thread\n");
+			if(pthread_setname_np(tcp_thread, "tcp ct listener") != 0)
+			{
+				IPACMERR("unable to set thread name\n");
+			}
+		}
+
+		if(!udp_thread)
+		{
+			ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+			if(0 != ret)
+			{
+				IPACMERR("unable to create UDP conntrack event listner thread\n");
+				PERROR("unable to create UDP conntrack\n");
+				goto error;
+			}
+
+			IPACMDBG("created UDP conntrack event listner thread\n");
+			if(pthread_setname_np(udp_thread, "udp ct listener") != 0)
+			{
+				IPACMERR("unable to set thread name\n");
+			}
+		}
+
+		isCTReg = true;
+	}
+
+	return 0;
+
+error:
+	return -1;
+}
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+	int ret;
+	pthread_t udpcto_thread = 0;
+
+	if(isNatThreadStart == false)
+	{
+		if(!udpcto_thread)
+		{
+			ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+			if(0 != ret)
+			{
+				IPACMERR("unable to create udp conn timeout thread\n");
+				PERROR("unable to create udp conn timeout\n");
+				goto error;
+			}
+
+			IPACMDBG("created upd conn timeout thread\n");
+			if(pthread_setname_np(udpcto_thread, "udp conn timeout") != 0)
+			{
+				IPACMERR("unable to set thread name\n");
+			}
+		}
+
+		isNatThreadStart = true;
+	}
+	return 0;
+
+error:
+	return -1;
+}
+
+void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
+{
+	 IPACMDBG_H("Deleting ipv4 nat table with");
+	 IPACMDBG_H(" public ip address(0x%x): %d.%d.%d.%d\n", wan_addr,
+		    ((wan_addr>>24) & 0xFF), ((wan_addr>>16) & 0xFF), 
+		    ((wan_addr>>8) & 0xFF), (wan_addr & 0xFF));
+	 
+	 WanUp = false;
+
+	 if(nat_inst != NULL)
+	 {
+		 nat_inst->DeleteTable(wan_addr);
+	 }
+}
+
+
+void ParseCTMessage(struct nf_conntrack *ct)
+{
+	 uint32_t status, timeout;
+	 IPACMDBG("Printing conntrack parameters\n");
+
+	 iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
+	 iptodot("ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST));
+	 IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
+	 IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
+
+	 iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
+	 iptodot("ATTR_REPL_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST));
+	 IPACMDBG("ATTR_REPL_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC));
+	 IPACMDBG("ATTR_REPL_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST));
+
+	 iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
+	 iptodot("ATTR_DNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_DNAT_IPV4));
+	 IPACMDBG("ATTR_SNAT_PORT: 0x%x\n", nfct_get_attr_u16(ct, ATTR_SNAT_PORT));
+	 IPACMDBG("ATTR_DNAT_PORT: 0x%x\n", nfct_get_attr_u16(ct, ATTR_DNAT_PORT));
+
+	 IPACMDBG("ATTR_MARK: 0x%x\n", nfct_get_attr_u32(ct, ATTR_MARK));
+	 IPACMDBG("ATTR_USE: 0x%x\n", nfct_get_attr_u32(ct, ATTR_USE));
+	 IPACMDBG("ATTR_ID: 0x%x\n", nfct_get_attr_u32(ct, ATTR_ID));
+
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	 IPACMDBG("ATTR_STATUS: 0x%x\n", status);
+
+	 timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+	 IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
+	 if(IPS_SRC_NAT & status)
+	 {
+			IPACMDBG("IPS_SRC_NAT set\n");
+	 }
+
+	 if(IPS_DST_NAT & status)
+	 {
+			IPACMDBG("IPS_DST_NAT set\n");
+	 }
+
+	 if(IPS_SRC_NAT_DONE & status)
+	 {
+			IPACMDBG("IPS_SRC_NAT_DONE set\n");
+	 }
+
+	 if(IPS_DST_NAT_DONE & status)
+	 {
+			IPACMDBG(" IPS_DST_NAT_DONE set\n");
+	 }
+
+	 IPACMDBG("\n");
+	 return;
+}
+
+void ParseCTV6Message(struct nf_conntrack *ct)
+{
+	 uint32_t status, timeout;
+	 struct nfct_attr_grp_ipv6 orig_params;
+	 uint8_t l4proto, tcp_flags, tcp_state;
+
+	 IPACMDBG("Printing conntrack parameters\n");
+
+	 nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+	 IPACMDBG("Orig src_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.src[0], orig_params.src[1],
+                	orig_params.src[2], orig_params.src[3]);
+	IPACMDBG("Orig dst_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.dst[0], orig_params.dst[1],
+                	orig_params.dst[2], orig_params.dst[3]);
+
+	 IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
+	 IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
+
+	 IPACMDBG("ATTR_MARK: 0x%x\n", nfct_get_attr_u32(ct, ATTR_MARK));
+	 IPACMDBG("ATTR_USE: 0x%x\n", nfct_get_attr_u32(ct, ATTR_USE));
+	 IPACMDBG("ATTR_ID: 0x%x\n", nfct_get_attr_u32(ct, ATTR_ID));
+
+	 timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+	 IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	 IPACMDBG("ATTR_STATUS: 0x%x\n", status);
+
+	 l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	 IPACMDBG("ATTR_ORIG_L4PROTO: 0x%x\n", l4proto);
+	 if(l4proto == IPPROTO_TCP)
+	 {
+		tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+		IPACMDBG("ATTR_TCP_STATE: 0x%x\n", tcp_state);
+
+		tcp_flags =  nfct_get_attr_u8(ct, ATTR_TCP_FLAGS_ORIG);
+		IPACMDBG("ATTR_TCP_FLAGS_ORIG: 0x%x\n", tcp_flags);
+	 }
+
+	 IPACMDBG("\n");
+	 return;
+}
+
+#ifdef CT_OPT
+void IPACM_ConntrackListener::ProcessCTV6Message(void *param)
+{
+	ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+	u_int8_t l4proto = 0;
+	uint32_t status = 0;
+	struct nf_conntrack *ct = evt_data->ct;
+
+#ifdef IPACM_DEBUG
+	 char buf[1024];
+
+	 /* Process message and generate ioctl call to kernel thread */
+	 nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+								 evt_data->type, NFCT_O_PLAIN, NFCT_OF_TIME);
+	 IPACMDBG("%s\n", buf);
+	 IPACMDBG("\n");
+	 ParseCTV6Message(ct);
+#endif
+
+	if(p_lan2lan == NULL)
+	{
+		IPACMERR("Lan2Lan Instance is null\n");
+		goto IGNORE;
+	}
+
+	status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	if((IPS_DST_NAT & status) || (IPS_SRC_NAT & status))
+	{
+		IPACMDBG("Either Destination or Source nat flag Set\n");
+		goto IGNORE;
+	}
+
+	l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+	{
+		 IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+		 goto IGNORE;
+	}
+
+	IPACMDBG("Neither Destination nor Source nat flag Set\n");
+	struct nfct_attr_grp_ipv6 orig_params;
+	nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+
+	ipacm_event_connection lan2lan_conn;
+	lan2lan_conn.iptype = IPA_IP_v6;
+	memcpy(lan2lan_conn.src_ipv6_addr, orig_params.src,
+				 sizeof(lan2lan_conn.src_ipv6_addr));
+    IPACMDBG("Before convert, src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+                	lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+    for(int cnt=0; cnt<4; cnt++)
+	{
+	   lan2lan_conn.src_ipv6_addr[cnt] = ntohl(lan2lan_conn.src_ipv6_addr[cnt]);
+	}
+	IPACMDBG("After convert src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+                	lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+
+	memcpy(lan2lan_conn.dst_ipv6_addr, orig_params.dst,
+				 sizeof(lan2lan_conn.dst_ipv6_addr));
+	IPACMDBG("Before convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+                	lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+    for(int cnt=0; cnt<4; cnt++)
+	{
+	   lan2lan_conn.dst_ipv6_addr[cnt] = ntohl(lan2lan_conn.dst_ipv6_addr[cnt]);
+	}
+	IPACMDBG("After convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+                	lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+
+	if(((IPPROTO_UDP == l4proto) && (NFCT_T_NEW == evt_data->type)) ||
+		 ((IPPROTO_TCP == l4proto) &&
+			(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED))
+		 )
+	{
+			p_lan2lan->handle_new_connection(&lan2lan_conn);
+	}
+	else if((IPPROTO_UDP == l4proto && NFCT_T_DESTROY == evt_data->type) ||
+					(IPPROTO_TCP == l4proto &&
+					 nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+	{
+			p_lan2lan->handle_del_connection(&lan2lan_conn);
+	}
+
+IGNORE:
+	/* Cleanup item that was allocated during the original CT callback */
+	nfct_destroy(ct);
+	return;
+}
+#endif
+
+void IPACM_ConntrackListener::ProcessCTMessage(void *param)
+{
+	 ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+	 u_int8_t l4proto = 0;
+
+#ifdef IPACM_DEBUG
+	 char buf[1024];
+	 unsigned int out_flags;
+
+	 /* Process message and generate ioctl call to kernel thread */
+	 out_flags = (NFCT_OF_SHOW_LAYER3 | NFCT_OF_TIME | NFCT_OF_ID);
+	 nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+								 evt_data->type, NFCT_O_PLAIN, out_flags);
+	 IPACMDBG_H("%s\n", buf);
+
+	 ParseCTMessage(evt_data->ct);
+#endif
+
+	 l4proto = nfct_get_attr_u8(evt_data->ct, ATTR_ORIG_L4PROTO);
+	 if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+	 {
+			IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+	 }
+	 else
+	 {
+			ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
+	 }
+
+	 /* Cleanup item that was allocated during the original CT callback */
+	 nfct_destroy(evt_data->ct);
+	 return;
+}
+
+bool IPACM_ConntrackListener::AddIface(
+   nat_table_entry *rule, bool *isTempEntry)
+{
+	int cnt;
+
+	*isTempEntry = false;
+
+	/* Special handling for Passthrough IP. */
+	if (IPACM_Iface::ipacmcfg->ipacm_ip_passthrough_mode)
+	{
+		if (rule->private_ip == IPACM_Wan::getWANIP())
+		{
+			IPACMDBG("In Passthrough mode and entry matched with Wan IP (0x%x)\n",
+				rule->private_ip);
+			return true;
+		}
+	}
+
+	/* check whether nat iface or not */
+	for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+	{
+		if (nat_iface_ipv4_addr[cnt] != 0)
+		{
+			if (rule->private_ip == nat_iface_ipv4_addr[cnt] ||
+				rule->target_ip == nat_iface_ipv4_addr[cnt])
+			{
+				IPACMDBG("matched nat_iface_ipv4_addr entry(%d)\n", cnt);
+				iptodot("AddIface(): Nat entry match with ip addr",
+						nat_iface_ipv4_addr[cnt]);
+				return true;
+			}
+		}
+	}
+
+	if (!isStaMode)
+	{
+		/* check whether non nat iface or not, on Non Nat iface
+		   add dummy rule by copying public ip to private ip */
+		for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+		{
+			if (nonnat_iface_ipv4_addr[cnt] != 0)
+			{
+				if (rule->private_ip == nonnat_iface_ipv4_addr[cnt] ||
+					rule->target_ip == nonnat_iface_ipv4_addr[cnt])
+				{
+					IPACMDBG("matched non_nat_iface_ipv4_addr entry(%d)\n", cnt);
+					iptodot("AddIface(): Non Nat entry match with ip addr",
+							nonnat_iface_ipv4_addr[cnt]);
+
+					rule->private_ip = rule->public_ip;
+					rule->private_port = rule->public_port;
+					return true;
+				}
+			}
+		}
+		IPACMDBG_H("Not mtaching with non-nat ifaces\n");
+	}
+	else
+		IPACMDBG("In STA mode, don't compare against non nat ifaces\n");
+
+	if(pConfig == NULL)
+	{
+		pConfig = IPACM_Config::GetInstance();
+		if(pConfig == NULL)
+		{
+			IPACMERR("Unable to get Config instance\n");
+			return false;
+		}
+	}
+
+	if (pConfig->isPrivateSubnet(rule->private_ip) ||
+		pConfig->isPrivateSubnet(rule->target_ip))
+	{
+		IPACMDBG("Matching with Private subnet\n");
+		*isTempEntry = true;
+		return true;
+	}
+
+	return false;
+}
+
+void IPACM_ConntrackListener::AddORDeleteNatEntry(const nat_entry_bundle *input)
+{
+	u_int8_t tcp_state;
+
+	if (nat_inst == NULL)
+	{
+		IPACMERR("Nat instance is NULL, unable to add or delete\n");
+		return;
+	}
+
+	IPACMDBG_H("Below Nat Entry will either be added or deleted\n");
+	iptodot("AddORDeleteNatEntry(): target ip or dst ip",
+			input->rule->target_ip);
+	IPACMDBG("target port or dst port: 0x%x Decimal:%d\n",
+			 input->rule->target_port, input->rule->target_port);
+	iptodot("AddORDeleteNatEntry(): private ip or src ip",
+			input->rule->private_ip);
+	IPACMDBG("private port or src port: 0x%x, Decimal:%d\n",
+			 input->rule->private_port, input->rule->private_port);
+	IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n",
+			 input->rule->public_port, input->rule->public_port);
+	IPACMDBG("Protocol: %d, destination nat flag: %d\n",
+			 input->rule->protocol, input->rule->dst_nat);
+
+	if (IPPROTO_TCP == input->rule->protocol)
+	{
+		tcp_state = nfct_get_attr_u8(input->ct, ATTR_TCP_STATE);
+		if (TCP_CONNTRACK_ESTABLISHED == tcp_state)
+		{
+			IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
+			if (!CtList->isWanUp())
+			{
+				IPACMDBG("Wan is not up, cache connections\n");
+				nat_inst->CacheEntry(input->rule);
+			}
+			else if (input->isTempEntry)
+			{
+				nat_inst->AddTempEntry(input->rule);
+			}
+			else
+			{
+				nat_inst->AddEntry(input->rule);
+			}
+		}
+		else if (TCP_CONNTRACK_FIN_WAIT == tcp_state ||
+				   input->type == NFCT_T_DESTROY)
+		{
+			IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d) "
+					 "or type NFCT_T_DESTROY(%d)\n", tcp_state, input->type);
+
+			nat_inst->DeleteEntry(input->rule);
+			nat_inst->DeleteTempEntry(input->rule);
+		}
+		else
+		{
+			IPACMDBG("Ignore tcp state: %d and type: %d\n",
+					 tcp_state, input->type);
+		}
+
+	}
+	else if (IPPROTO_UDP == input->rule->protocol)
+	{
+		if (NFCT_T_NEW == input->type)
+		{
+			IPACMDBG("New UDP connection at time %ld\n", time(NULL));
+			if (!CtList->isWanUp())
+			{
+				IPACMDBG("Wan is not up, cache connections\n");
+				nat_inst->CacheEntry(input->rule);
+			}
+			else if (input->isTempEntry)
+			{
+				nat_inst->AddTempEntry(input->rule);
+			}
+			else
+			{
+				nat_inst->AddEntry(input->rule);
+			}
+		}
+		else if (NFCT_T_DESTROY == input->type)
+		{
+			IPACMDBG("UDP connection close at time %ld\n", time(NULL));
+			nat_inst->DeleteEntry(input->rule);
+			nat_inst->DeleteTempEntry(input->rule);
+		}
+	}
+
+	return;
+}
+
+void IPACM_ConntrackListener::PopulateTCPorUDPEntry(
+	 struct nf_conntrack *ct,
+	 uint32_t status,
+	 nat_table_entry *rule)
+{
+	if (IPS_DST_NAT == status)
+	{
+		IPACMDBG("Destination NAT\n");
+		rule->dst_nat = true;
+
+		IPACMDBG("Parse reply tuple\n");
+		rule->target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+		rule->target_ip = ntohl(rule->target_ip);
+		iptodot("PopulateTCPorUDPEntry(): target ip", rule->target_ip);
+
+		/* Retriev target/dst port */
+		rule->target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+		rule->target_port = ntohs(rule->target_port);
+		if (0 == rule->target_port)
+		{
+			IPACMDBG("unable to retrieve target port\n");
+		}
+
+		rule->public_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+		rule->public_port = ntohs(rule->public_port);
+
+		/* Retriev src/private ip address */
+		rule->private_ip = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC);
+		rule->private_ip = ntohl(rule->private_ip);
+		iptodot("PopulateTCPorUDPEntry(): private ip", rule->private_ip);
+		if (0 == rule->private_ip)
+		{
+			IPACMDBG("unable to retrieve private ip address\n");
+		}
+
+		/* Retriev src/private port */
+		rule->private_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
+		rule->private_port = ntohs(rule->private_port);
+		if (0 == rule->private_port)
+		{
+			IPACMDBG("unable to retrieve private port\n");
+		}
+	}
+	else if (IPS_SRC_NAT == status)
+	{
+		IPACMDBG("Source NAT\n");
+		rule->dst_nat = false;
+
+		/* Retriev target/dst ip address */
+		IPACMDBG("Parse source tuple\n");
+		rule->target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+		rule->target_ip = ntohl(rule->target_ip);
+		iptodot("PopulateTCPorUDPEntry(): target ip", rule->target_ip);
+		if (0 == rule->target_ip)
+		{
+			IPACMDBG("unable to retrieve target ip address\n");
+		}
+		/* Retriev target/dst port */
+		rule->target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+		rule->target_port = ntohs(rule->target_port);
+		if (0 == rule->target_port)
+		{
+			IPACMDBG("unable to retrieve target port\n");
+		}
+
+		/* Retriev public port */
+		rule->public_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
+		rule->public_port = ntohs(rule->public_port);
+		if (0 == rule->public_port)
+		{
+			IPACMDBG("unable to retrieve public port\n");
+		}
+
+		/* Retriev src/private ip address */
+		rule->private_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+		rule->private_ip = ntohl(rule->private_ip);
+		iptodot("PopulateTCPorUDPEntry(): private ip", rule->private_ip);
+		if (0 == rule->private_ip)
+		{
+			IPACMDBG("unable to retrieve private ip address\n");
+		}
+
+		/* Retriev src/private port */
+		rule->private_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+		rule->private_port = ntohs(rule->private_port);
+		if (0 == rule->private_port)
+		{
+			IPACMDBG("unable to retrieve private port\n");
+		}
+	}
+
+	return;
+}
+
+#ifdef CT_OPT
+void IPACM_ConntrackListener::HandleLan2Lan(struct nf_conntrack *ct,
+	enum nf_conntrack_msg_type type,
+	 nat_table_entry *rule)
+{
+	ipacm_event_connection lan2lan_conn = { 0 };
+
+	if (p_lan2lan == NULL)
+	{
+		IPACMERR("Lan2Lan Instance is null\n");
+		return;
+	}
+
+	lan2lan_conn.iptype = IPA_IP_v4;
+	lan2lan_conn.src_ipv4_addr = orig_src_ip;
+	lan2lan_conn.dst_ipv4_addr = orig_dst_ip;
+
+	if (((IPPROTO_UDP == rule->protocol) && (NFCT_T_NEW == type)) ||
+		((IPPROTO_TCP == rule->protocol) && (nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED)))
+	{
+		p_lan2lan->handle_new_connection(&lan2lan_conn);
+	}
+	else if ((IPPROTO_UDP == rule->protocol && NFCT_T_DESTROY == type) ||
+			   (IPPROTO_TCP == rule->protocol &&
+				nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+	{
+		p_lan2lan->handle_del_connection(&lan2lan_conn);
+	}
+}
+#endif
+
+void IPACM_ConntrackListener::CheckSTAClient(
+   const nat_table_entry *rule, bool *isTempEntry)
+{
+	int nCnt;
+
+	/* Check whether target is in STA client list or not
+      if not ignore the connection */
+	 if(!isStaMode || (StaClntCnt == 0))
+	 {
+		return;
+	 }
+
+	 if((sta_clnt_ipv4_addr[0] & STA_CLNT_SUBNET_MASK) !=
+		 (rule->target_ip & STA_CLNT_SUBNET_MASK))
+	 {
+		IPACMDBG("STA client subnet mask not matching\n");
+		return;
+	 }
+
+	 IPACMDBG("StaClntCnt %d\n", StaClntCnt);
+	 for(nCnt = 0; nCnt < StaClntCnt; nCnt++)
+	 {
+		IPACMDBG("Comparing trgt_ip 0x%x with sta clnt ip: 0x%x\n",
+			 rule->target_ip, sta_clnt_ipv4_addr[nCnt]);
+		if(rule->target_ip == sta_clnt_ipv4_addr[nCnt])
+		{
+			IPACMDBG("Match index %d\n", nCnt);
+			return;
+		}
+	 }
+
+	IPACMDBG_H("Not matching with STA Clnt Ip Addrs 0x%x\n",
+		rule->target_ip);
+	*isTempEntry = true;
+}
+
+/* conntrack send in host order and ipa expects in host order */
+void IPACM_ConntrackListener::ProcessTCPorUDPMsg(
+	 struct nf_conntrack *ct,
+	 enum nf_conntrack_msg_type type,
+	 u_int8_t l4proto)
+{
+	 nat_table_entry rule;
+	 uint32_t status = 0;
+	 uint32_t orig_src_ip, orig_dst_ip;
+	 bool isAdd = false;
+
+	 nat_entry_bundle nat_entry;
+	 nat_entry.isTempEntry = false;
+	 nat_entry.ct = ct;
+	 nat_entry.type = type;
+
+ 	 memset(&rule, 0, sizeof(rule));
+	 IPACMDBG("Received type:%d with proto:%d\n", type, l4proto);
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+
+	 /* Retrieve Protocol */
+	 rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
+	 if(IPS_DST_NAT & status)
+	 {
+		 status = IPS_DST_NAT;
+	 }
+	 else if(IPS_SRC_NAT & status)
+	 {
+		 status = IPS_SRC_NAT;
+	 }
+	 else
+	 {
+		 IPACMDBG("Neither Destination nor Source nat flag Set\n");
+		 orig_src_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+		 orig_src_ip = ntohl(orig_src_ip);
+		 if(orig_src_ip == 0)
+		 {
+			 IPACMERR("unable to retrieve orig src ip address\n");
+			 return;
+		 }
+
+		 orig_dst_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+		 orig_dst_ip = ntohl(orig_dst_ip);
+		 if(orig_dst_ip == 0)
+		 {
+			 IPACMERR("unable to retrieve orig dst ip address\n");
+			 return;
+		 }
+
+		if(orig_src_ip == wan_ipaddr)
+		{
+			IPACMDBG("orig src ip:0x%x equal to wan ip\n",orig_src_ip);
+			status = IPS_SRC_NAT;
+		}
+		else if(orig_dst_ip == wan_ipaddr)
+		{
+			IPACMDBG("orig Dst IP:0x%x equal to wan ip\n",orig_dst_ip);
+			status = IPS_DST_NAT;
+		}
+		else
+		{
+			IPACMDBG_H("Neither orig src ip:0x%x Nor orig Dst IP:0x%x equal to wan ip:0x%x\n",
+					   orig_src_ip, orig_dst_ip, wan_ipaddr);
+
+#ifdef CT_OPT
+			HandleLan2Lan(ct, type, &rule);
+#endif
+			return;
+		}
+	 }
+
+	 if(IPS_DST_NAT == status || IPS_SRC_NAT == status)
+	 {
+		 PopulateTCPorUDPEntry(ct, status, &rule);
+		 rule.public_ip = wan_ipaddr;
+	 }
+	 else
+	 {
+		 IPACMDBG("Neither source Nor destination nat\n");
+		 goto IGNORE;
+	 }
+
+	 if (rule.private_ip != wan_ipaddr)
+	 {
+		 isAdd = AddIface(&rule, &nat_entry.isTempEntry);
+		 if (!isAdd)
+		 {
+			 goto IGNORE;
+		 }
+	 }
+	 else
+	 {
+		 if (isStaMode)
+		 {
+			 IPACMDBG("In STA mode, ignore connections destinated to STA interface\n");
+			 goto IGNORE;
+		 }
+
+		 IPACMDBG("For embedded connections add dummy nat rule\n");
+		 IPACMDBG("Change private port %d to %d\n",
+				  rule.private_port, rule.public_port);
+		 rule.private_port = rule.public_port;
+	 }
+
+	 CheckSTAClient(&rule, &nat_entry.isTempEntry);
+	 nat_entry.rule = &rule;
+	 AddORDeleteNatEntry(&nat_entry);
+	 return;
+
+IGNORE:
+	IPACMDBG_H("ignoring below Nat Entry\n");
+	iptodot("ProcessTCPorUDPMsg(): target ip or dst ip", rule.target_ip);
+	IPACMDBG("target port or dst port: 0x%x Decimal:%d\n", rule.target_port, rule.target_port);
+	iptodot("ProcessTCPorUDPMsg(): private ip or src ip", rule.private_ip);
+	IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
+	IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
+	IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
+	return;
+}
+
+void IPACM_ConntrackListener::HandleSTAClientAddEvt(uint32_t clnt_ip_addr)
+{
+	 int cnt;
+	 IPACMDBG_H("Received STA client 0x%x\n", clnt_ip_addr);
+
+	 if(StaClntCnt >= MAX_STA_CLNT_IFACES)
+	 {
+		IPACMDBG("Max STA client reached, ignore 0x%x\n", clnt_ip_addr);
+		return;
+	 }
+
+	 for(cnt=0; cnt<MAX_STA_CLNT_IFACES; cnt++)
+	 {
+		if(sta_clnt_ipv4_addr[cnt] != 0 &&
+		 sta_clnt_ipv4_addr[cnt] == clnt_ip_addr)
+		{
+			IPACMDBG("Ignoring duplicate one 0x%x\n", clnt_ip_addr);
+			break;
+		}
+
+		if(sta_clnt_ipv4_addr[cnt] == 0)
+		{
+			IPACMDBG("Adding STA client 0x%x at Index: %d\n",
+					clnt_ip_addr, cnt);
+			sta_clnt_ipv4_addr[cnt] = clnt_ip_addr;
+			StaClntCnt++;
+			IPACMDBG("STA client cnt %d\n", StaClntCnt);
+			break;
+		}
+
+	 }
+
+	 nat_inst->FlushTempEntries(clnt_ip_addr, true);
+	 return;
+}
+
+void IPACM_ConntrackListener::HandleSTAClientDelEvt(uint32_t clnt_ip_addr)
+{
+	 int cnt;
+	 IPACMDBG_H("Received STA client 0x%x\n", clnt_ip_addr);
+
+	 for(cnt=0; cnt<MAX_STA_CLNT_IFACES; cnt++)
+	 {
+		if(sta_clnt_ipv4_addr[cnt] != 0 &&
+		 sta_clnt_ipv4_addr[cnt] == clnt_ip_addr)
+		{
+			IPACMDBG("Deleting STA client 0x%x at index: %d\n",
+					clnt_ip_addr, cnt);
+			sta_clnt_ipv4_addr[cnt] = 0;
+			nat_inst->DelEntriesOnSTAClntDiscon(clnt_ip_addr);
+			StaClntCnt--;
+			IPACMDBG("STA client cnt %d\n", StaClntCnt);
+			break;
+		}
+	 }
+
+	 nat_inst->FlushTempEntries(clnt_ip_addr, false);
+   return;
+}
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
new file mode 100644
index 0000000..f0bdd99
--- /dev/null
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -0,0 +1,969 @@
+/*
+Copyright (c) 2013-2016, 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 "IPACM_Conntrack_NATApp.h"
+#include "IPACM_ConntrackClient.h"
+
+#define INVALID_IP_ADDR 0x0
+
+/* NatApp class Implementation */
+NatApp *NatApp::pInstance = NULL;
+NatApp::NatApp()
+{
+	max_entries = 0;
+	cache = NULL;
+
+	nat_table_hdl = 0;
+	pub_ip_addr = 0;
+
+	curCnt = 0;
+
+	pALGPorts = NULL;
+	nALGPort = 0;
+
+	ct = NULL;
+	ct_hdl = NULL;
+
+	memset(temp, 0, sizeof(temp));
+}
+
+int NatApp::Init(void)
+{
+	IPACM_Config *pConfig;
+	int size = 0;
+
+	pConfig = IPACM_Config::GetInstance();
+	if(pConfig == NULL)
+	{
+		IPACMERR("Unable to get Config instance\n");
+		return -1;
+	}
+
+	max_entries = pConfig->GetNatMaxEntries();
+
+	size = (sizeof(nat_table_entry) * max_entries);
+	cache = (nat_table_entry *)malloc(size);
+	if(cache == NULL)
+	{
+		IPACMERR("Unable to allocate memory for cache\n");
+		goto fail;
+	}
+	IPACMDBG("Allocated %d bytes for config manager nat cache\n", size);
+	memset(cache, 0, size);
+
+	nALGPort = pConfig->GetAlgPortCnt();
+	if(nALGPort > 0)
+	{
+		pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
+		if(pALGPorts == NULL)
+		{
+			IPACMERR("Unable to allocate memory for alg prots\n");
+			goto fail;
+		}
+		memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
+
+		if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
+		{
+			IPACMERR("Unable to retrieve ALG prots\n");
+			goto fail;
+		}
+
+		IPACMDBG("Printing %d alg ports information\n", nALGPort);
+		for(int cnt=0; cnt<nALGPort; cnt++)
+		{
+			IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+		}
+	}
+
+	return 0;
+
+fail:
+	free(cache);
+	free(pALGPorts);
+	return -1;
+}
+
+NatApp* NatApp::GetInstance()
+{
+	if(pInstance == NULL)
+	{
+		pInstance = new NatApp();
+
+		if(pInstance->Init())
+		{
+			delete pInstance;
+			return NULL;
+		}
+	}
+
+	return pInstance;
+}
+
+/* NAT APP related object function definitions */
+
+int NatApp::AddTable(uint32_t pub_ip)
+{
+	int ret;
+	int cnt = 0;
+	ipa_nat_ipv4_rule nat_rule;
+	IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
+
+	/* Not reset the cache wait it timeout by destroy event */
+#if 0
+	if (pub_ip != pub_ip_addr_pre)
+	{
+		IPACMDBG("Reset the cache because NAT-ipv4 different\n");
+		memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+		curCnt = 0;
+	}
+#endif
+	ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
+	if(ret)
+	{
+		IPACMERR("unable to create nat table Error:%d\n", ret);
+		return ret;
+	}
+
+	/* Add back the cached NAT-entry */
+	if (pub_ip == pub_ip_addr_pre)
+	{
+		IPACMDBG("Restore the cache to ipa NAT-table\n");
+		for(cnt = 0; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip !=0)
+			{
+				memset(&nat_rule, 0 , sizeof(nat_rule));
+				nat_rule.private_ip = cache[cnt].private_ip;
+				nat_rule.target_ip = cache[cnt].target_ip;
+				nat_rule.target_port = cache[cnt].target_port;
+				nat_rule.private_port = cache[cnt].private_port;
+				nat_rule.public_port = cache[cnt].public_port;
+				nat_rule.protocol = cache[cnt].protocol;
+
+				if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to add the rule delete from cache\n");
+					memset(&cache[cnt], 0, sizeof(cache[cnt]));
+					curCnt--;
+					continue;
+				}
+				cache[cnt].enabled = true;
+
+				IPACMDBG("On wan-iface reset added below rule successfully\n");
+				iptodot("Private IP", nat_rule.private_ip);
+				iptodot("Target IP", nat_rule.target_ip);
+				IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+				IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+				IPACMDBG("protocol: %d\n", nat_rule.protocol);
+			}
+		}
+	}
+
+	pub_ip_addr = pub_ip;
+	return 0;
+}
+
+void NatApp::Reset()
+{
+	int cnt = 0;
+
+	nat_table_hdl = 0;
+	pub_ip_addr = 0;
+	/* NAT tbl deleted, reset enabled bit */
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		cache[cnt].enabled = false;
+	}
+}
+
+int NatApp::DeleteTable(uint32_t pub_ip)
+{
+	int ret;
+	IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
+
+	CHK_TBL_HDL();
+
+	if(pub_ip_addr != pub_ip)
+	{
+		IPACMDBG("Public ip address is not matching\n");
+		IPACMERR("unable to delete the nat table\n");
+		return -1;
+	}
+
+	ret = ipa_nat_del_ipv4_tbl(nat_table_hdl);
+	if(ret)
+	{
+		IPACMERR("unable to delete nat table Error: %d\n", ret);;
+		return ret;
+	}
+
+	pub_ip_addr_pre = pub_ip_addr;
+	Reset();
+	return 0;
+}
+
+/* Check for duplicate entries */
+bool NatApp::ChkForDup(const nat_table_entry *rule)
+{
+	int cnt = 0;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	for(; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == rule->private_ip &&
+			 cache[cnt].target_ip == rule->target_ip &&
+			 cache[cnt].private_port ==  rule->private_port  &&
+			 cache[cnt].target_port == rule->target_port &&
+			 cache[cnt].protocol == rule->protocol)
+		{
+			log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+			rule->target_port,"Duplicate Rule\n");
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/* Delete the entry from Nat table on connection close */
+int NatApp::DeleteEntry(const nat_table_entry *rule)
+{
+	int cnt = 0;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+	rule->target_port,"for deletion\n");
+
+
+	for(; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == rule->private_ip &&
+			 cache[cnt].target_ip == rule->target_ip &&
+			 cache[cnt].private_port ==  rule->private_port  &&
+			 cache[cnt].target_port == rule->target_port &&
+			 cache[cnt].protocol == rule->protocol)
+		{
+
+			if(cache[cnt].enabled == true)
+			{
+				if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
+				}
+
+				IPACMDBG_H("Deleted Nat entry(%d) Successfully\n", cnt);
+			}
+			else
+			{
+				IPACMDBG_H("Deleted Nat entry(%d) only from cache\n", cnt);
+			}
+
+			memset(&cache[cnt], 0, sizeof(cache[cnt]));
+			curCnt--;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* Add new entry to the nat table on new connection */
+int NatApp::AddEntry(const nat_table_entry *rule)
+{
+	int cnt = 0;
+	ipa_nat_ipv4_rule nat_rule;
+
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	CHK_TBL_HDL();
+	log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+	rule->target_port,"for addition\n");
+	if(isAlgPort(rule->protocol, rule->private_port) ||
+		 isAlgPort(rule->protocol, rule->target_port))
+	{
+		IPACMERR("connection using ALG Port, ignore\n");
+		return -1;
+	}
+
+	if(rule->private_ip == 0 ||
+		 rule->target_ip == 0 ||
+		 rule->private_port == 0  ||
+		 rule->target_port == 0 ||
+		 rule->protocol == 0)
+	{
+		IPACMERR("Invalid Connection, ignoring it\n");
+		return 0;
+	}
+
+	if(!ChkForDup(rule))
+	{
+		for(; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip == 0 &&
+				 cache[cnt].target_ip == 0 &&
+				 cache[cnt].private_port == 0  &&
+				 cache[cnt].target_port == 0 &&
+				 cache[cnt].protocol == 0)
+			{
+				break;
+			}
+		}
+
+		if(max_entries == cnt)
+		{
+			IPACMERR("Error: Unable to add, reached maximum rules\n");
+			return -1;
+		}
+		else
+		{
+			nat_rule.private_ip = rule->private_ip;
+			nat_rule.target_ip = rule->target_ip;
+			nat_rule.target_port = rule->target_port;
+			nat_rule.private_port = rule->private_port;
+			nat_rule.public_port = rule->public_port;
+			nat_rule.protocol = rule->protocol;
+
+			if(isPwrSaveIf(rule->private_ip) ||
+				 isPwrSaveIf(rule->target_ip))
+			{
+				IPACMDBG("Device is Power Save mode: Dont insert into nat table but cache\n");
+				cache[cnt].enabled = false;
+				cache[cnt].rule_hdl = 0;
+			}
+			else
+			{
+
+				if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to add the rule\n");
+					return -1;
+				}
+
+				cache[cnt].enabled = true;
+			}
+
+			cache[cnt].private_ip = rule->private_ip;
+			cache[cnt].target_ip = rule->target_ip;
+			cache[cnt].target_port = rule->target_port;
+			cache[cnt].private_port = rule->private_port;
+			cache[cnt].protocol = rule->protocol;
+			cache[cnt].timestamp = 0;
+			cache[cnt].public_port = rule->public_port;
+			cache[cnt].dst_nat = rule->dst_nat;
+			curCnt++;
+		}
+
+	}
+	else
+	{
+		IPACMERR("Duplicate rule. Ignore it\n");
+		return -1;
+	}
+
+	if(cache[cnt].enabled == true)
+	{
+		IPACMDBG_H("Added rule(%d) successfully\n", cnt);
+	}
+  else
+  {
+    IPACMDBG_H("Cached rule(%d) successfully\n", cnt);
+  }
+
+	return 0;
+}
+
+void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
+{
+	int ret;
+
+	iptodot("Private IP:", rule->private_ip);
+	iptodot("Target IP:",  rule->target_ip);
+	IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
+
+	if(!ct_hdl)
+	{
+		ct_hdl = nfct_open(CONNTRACK, 0);
+		if(!ct_hdl)
+		{
+			PERROR("nfct_open");
+			return;
+		}
+	}
+
+	if(!ct)
+	{
+		ct = nfct_new();
+		if(!ct)
+		{
+			PERROR("nfct_new");
+			return;
+		}
+	}
+
+	nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
+	if(rule->protocol == IPPROTO_UDP)
+	{
+		nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+		nfct_set_attr_u32(ct, ATTR_TIMEOUT, udp_timeout);
+	}
+	else
+	{
+		nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+		nfct_set_attr_u32(ct, ATTR_TIMEOUT, tcp_timeout);
+	}
+
+	if(rule->dst_nat == false)
+	{
+		nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->private_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->private_port));
+
+		nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(rule->target_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->target_port));
+
+		IPACMDBG("dst nat is not set\n");
+	}
+	else
+	{
+		nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->target_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->target_port));
+
+		nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(pub_ip_addr));
+		nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->public_port));
+
+		IPACMDBG("dst nat is set\n");
+	}
+
+	iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
+	iptodot("Destination IP:",  nfct_get_attr_u32(ct, ATTR_IPV4_DST));
+	IPACMDBG("Source Port: %d, Destination Port: %d\n",
+					 nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST));
+
+	IPACMDBG("updating %d connection with time: %d\n",
+					 rule->protocol, nfct_get_attr_u32(ct, ATTR_TIMEOUT));
+
+	ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
+	if(ret == -1)
+	{
+		IPACMERR("unable to update time stamp");
+		DeleteEntry(rule);
+	}
+	else
+	{
+		rule->timestamp = new_ts;
+		IPACMDBG("Updated time stamp successfully\n");
+	}
+
+	return;
+}
+
+void NatApp::UpdateUDPTimeStamp()
+{
+	int cnt;
+	uint32_t ts;
+	bool read_to = false;
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		ts = 0;
+		if(cache[cnt].enabled == true &&
+		   (cache[cnt].private_ip != cache[cnt].public_ip))
+		{
+			IPACMDBG("\n");
+			if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
+			{
+				IPACMERR("unable to retrieve timeout for rule hanle: %d\n", cache[cnt].rule_hdl);
+				continue;
+			}
+
+			if(cache[cnt].timestamp == ts)
+			{
+				IPACMDBG("No Change in Time Stamp: cahce:%d, ipahw:%d\n",
+								                  cache[cnt].timestamp, ts);
+				continue;
+			}
+
+			if (read_to == false) {
+				read_to = true;
+				Read_TcpUdp_Timeout();
+			}
+
+			UpdateCTUdpTs(&cache[cnt], ts);
+		} /* end of outer if */
+
+	} /* end of for loop */
+
+}
+
+bool NatApp::isAlgPort(uint8_t proto, uint16_t port)
+{
+	int cnt;
+	for(cnt = 0; cnt < nALGPort; cnt++)
+	{
+		if(proto == pALGPorts[cnt].protocol &&
+			 port == pALGPorts[cnt].port)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool NatApp::isPwrSaveIf(uint32_t ip_addr)
+{
+	int cnt;
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(0 != PwrSaveIfs[cnt] &&
+			 ip_addr == PwrSaveIfs[cnt])
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+int NatApp::UpdatePwrSaveIf(uint32_t client_lan_ip)
+{
+	int cnt;
+	IPACMDBG_H("Received IP address: 0x%x\n", client_lan_ip);
+
+	if(client_lan_ip == INVALID_IP_ADDR)
+	{
+		IPACMERR("Invalid ip address received\n");
+		return -1;
+	}
+
+	/* check for duplicate events */
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == client_lan_ip)
+		{
+			IPACMDBG("The client 0x%x is already in power save\n", client_lan_ip);
+			return 0;
+		}
+	}
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == 0)
+		{
+			PwrSaveIfs[cnt] = client_lan_ip;
+			break;
+		}
+	}
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == client_lan_ip &&
+			 cache[cnt].enabled == true)
+		{
+			if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("unable to delete the rule\n");
+				continue;
+			}
+
+			cache[cnt].enabled = false;
+			cache[cnt].rule_hdl = 0;
+		}
+	}
+
+	return 0;
+}
+
+int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
+{
+	int cnt;
+	ipa_nat_ipv4_rule nat_rule;
+
+	IPACMDBG_H("Received ip address: 0x%x\n", client_lan_ip);
+
+	if(client_lan_ip == INVALID_IP_ADDR)
+	{
+		IPACMERR("Invalid ip address received\n");
+		return -1;
+	}
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == client_lan_ip)
+		{
+			PwrSaveIfs[cnt] = 0;
+			break;
+		}
+	}
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
+
+		if(cache[cnt].private_ip == client_lan_ip &&
+			 cache[cnt].enabled == false)
+		{
+			memset(&nat_rule, 0 , sizeof(nat_rule));
+			nat_rule.private_ip = cache[cnt].private_ip;
+			nat_rule.target_ip = cache[cnt].target_ip;
+			nat_rule.target_port = cache[cnt].target_port;
+			nat_rule.private_port = cache[cnt].private_port;
+			nat_rule.public_port = cache[cnt].public_port;
+			nat_rule.protocol = cache[cnt].protocol;
+
+			if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("unable to add the rule delete from cache\n");
+				memset(&cache[cnt], 0, sizeof(cache[cnt]));
+				curCnt--;
+				continue;
+			}
+			cache[cnt].enabled = true;
+
+			IPACMDBG("On power reset added below rule successfully\n");
+			iptodot("Private IP", nat_rule.private_ip);
+			iptodot("Target IP", nat_rule.target_ip);
+			IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+			IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+			IPACMDBG("protocol: %d\n", nat_rule.protocol);
+
+		}
+	}
+
+	return -1;
+}
+
+uint32_t NatApp::GetTableHdl(uint32_t in_ip_addr)
+{
+	if(in_ip_addr == pub_ip_addr)
+	{
+		return nat_table_hdl;
+	}
+
+	return -1;
+}
+
+void NatApp::AddTempEntry(const nat_table_entry *new_entry)
+{
+	int cnt;
+
+	IPACMDBG("Received below Temp Nat entry\n");
+	iptodot("Private IP", new_entry->private_ip);
+	iptodot("Target IP", new_entry->target_ip);
+	IPACMDBG("Private Port: %d\t Target Port: %d\t", new_entry->private_port, new_entry->target_port);
+	IPACMDBG("protocolcol: %d\n", new_entry->protocol);
+
+	if(isAlgPort(new_entry->protocol, new_entry->private_port) ||
+		 isAlgPort(new_entry->protocol, new_entry->target_port))
+	{
+		IPACMDBG("connection using ALG Port. Dont insert into nat cache\n");
+		return;
+	}
+
+	if(ChkForDup(new_entry))
+	{
+		return;
+	}
+
+	for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+	{
+		if(temp[cnt].private_ip == new_entry->private_ip &&
+			 temp[cnt].target_ip == new_entry->target_ip &&
+			 temp[cnt].private_port ==  new_entry->private_port  &&
+			 temp[cnt].target_port == new_entry->target_port &&
+			 temp[cnt].protocol == new_entry->protocol)
+		{
+			IPACMDBG("Received duplicate Temp entry\n");
+			return;
+		}
+	}
+
+	for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+	{
+		if(temp[cnt].private_ip == 0 &&
+			 temp[cnt].target_ip == 0)
+		{
+			memcpy(&temp[cnt], new_entry, sizeof(nat_table_entry));
+			IPACMDBG("Added Temp Entry\n");
+			return;
+		}
+	}
+
+	IPACMDBG("Unable to add temp entry, cache full\n");
+	return;
+}
+
+void NatApp::DeleteTempEntry(const nat_table_entry *entry)
+{
+	int cnt;
+
+	IPACMDBG("Received below nat entry\n");
+	iptodot("Private IP", entry->private_ip);
+	iptodot("Target IP", entry->target_ip);
+	IPACMDBG("Private Port: %d\t Target Port: %d\n", entry->private_port, entry->target_port);
+	IPACMDBG("protocol: %d\n", entry->protocol);
+
+	for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+	{
+		if(temp[cnt].private_ip == entry->private_ip &&
+			 temp[cnt].target_ip == entry->target_ip &&
+			 temp[cnt].private_port ==  entry->private_port  &&
+			 temp[cnt].target_port == entry->target_port &&
+			 temp[cnt].protocol == entry->protocol)
+		{
+			memset(&temp[cnt], 0, sizeof(nat_table_entry));
+			IPACMDBG("Delete Temp Entry\n");
+			return;
+		}
+	}
+
+	IPACMDBG("No Such Temp Entry exists\n");
+	return;
+}
+
+void NatApp::FlushTempEntries(uint32_t ip_addr, bool isAdd,
+		bool isDummy)
+{
+	int cnt;
+	int ret;
+
+	IPACMDBG_H("Received below with isAdd:%d ", isAdd);
+	iptodot("IP Address: ", ip_addr);
+
+	for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+	{
+		if(temp[cnt].private_ip == ip_addr ||
+			 temp[cnt].target_ip == ip_addr)
+		{
+			if(isAdd)
+			{
+				if(temp[cnt].public_ip == pub_ip_addr)
+				{
+					if (isDummy) {
+						/* To avoild DL expections for non IPA path */
+						temp[cnt].private_ip = temp[cnt].public_ip;
+						temp[cnt].private_port = temp[cnt].public_port;
+						IPACMDBG("Flushing dummy temp rule");
+						iptodot("Private IP", temp[cnt].private_ip);
+					}
+
+					ret = AddEntry(&temp[cnt]);
+					if(ret)
+					{
+						IPACMERR("unable to add temp entry: %d\n", ret);
+						continue;
+					}
+				}
+			}
+			memset(&temp[cnt], 0, sizeof(nat_table_entry));
+		}
+	}
+
+	return;
+}
+
+int NatApp::DelEntriesOnClntDiscon(uint32_t ip_addr)
+{
+	int cnt, tmp = 0;
+	IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
+
+	if(ip_addr == INVALID_IP_ADDR)
+	{
+		IPACMERR("Invalid ip address received\n");
+		return -1;
+	}
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == ip_addr)
+		{
+			PwrSaveIfs[cnt] = 0;
+			IPACMDBG("Remove %d power save entry\n", cnt);
+			break;
+		}
+	}
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == ip_addr)
+		{
+			if(cache[cnt].enabled == true)
+			{
+				if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to delete the rule\n");
+					continue;
+				}
+				else
+				{
+					IPACMDBG("won't delete the rule\n");
+					cache[cnt].enabled = false;
+					tmp++;
+				}
+			}
+			IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
+		}
+	}
+
+	IPACMDBG("Deleted (but cached) %d entries\n", tmp);
+	return 0;
+}
+
+int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
+{
+	int cnt, tmp = curCnt;
+	IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
+
+	if(ip_addr == INVALID_IP_ADDR)
+	{
+		IPACMERR("Invalid ip address received\n");
+		return -1;
+	}
+
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].target_ip == ip_addr)
+		{
+			if(cache[cnt].enabled == true)
+			{
+				if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to delete the rule\n");
+					continue;
+				}
+			}
+
+			memset(&cache[cnt], 0, sizeof(cache[cnt]));
+			curCnt--;
+		}
+	}
+
+	IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
+	return 0;
+}
+
+void NatApp::CacheEntry(const nat_table_entry *rule)
+{
+	int cnt;
+
+	if(rule->private_ip == 0 ||
+		 rule->target_ip == 0 ||
+		 rule->private_port == 0  ||
+		 rule->target_port == 0 ||
+		 rule->protocol == 0)
+	{
+		IPACMERR("Invalid Connection, ignoring it\n");
+		return;
+	}
+
+	if(!ChkForDup(rule))
+	{
+		for(cnt=0; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip == 0 &&
+				 cache[cnt].target_ip == 0 &&
+				 cache[cnt].private_port == 0  &&
+				 cache[cnt].target_port == 0 &&
+				 cache[cnt].protocol == 0)
+			{
+				break;
+			}
+		}
+
+		if(max_entries == cnt)
+		{
+			IPACMERR("Error: Unable to add, reached maximum rules\n");
+			return;
+		}
+		else
+		{
+			cache[cnt].enabled = false;
+			cache[cnt].rule_hdl = 0;
+			cache[cnt].private_ip = rule->private_ip;
+			cache[cnt].target_ip = rule->target_ip;
+			cache[cnt].target_port = rule->target_port;
+			cache[cnt].private_port = rule->private_port;
+			cache[cnt].protocol = rule->protocol;
+			cache[cnt].timestamp = 0;
+			cache[cnt].public_port = rule->public_port;
+			cache[cnt].public_ip = rule->public_ip;
+			cache[cnt].dst_nat = rule->dst_nat;
+			curCnt++;
+		}
+
+	}
+	else
+	{
+		IPACMERR("Duplicate rule. Ignore it\n");
+		return;
+	}
+
+	IPACMDBG("Cached rule(%d) successfully\n", cnt);
+	return;
+}
+
+void NatApp::Read_TcpUdp_Timeout(void) {
+	FILE *udp_fd = NULL, *tcp_fd = NULL;
+
+	/* Read UDP timeout value */
+	udp_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
+	if (udp_fd == NULL) {
+		IPACMERR("unable to open %s\n", IPACM_UDP_FULL_FILE_NAME);
+		goto fail;
+	}
+
+	if (fscanf(udp_fd, "%d", &udp_timeout) != 1) {
+		IPACMERR("Error reading udp timeout\n");
+	}
+	IPACMDBG_H("udp timeout value: %d\n", udp_timeout);
+
+
+	/* Read TCP timeout value */
+	tcp_fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
+	if (tcp_fd == NULL) {
+		IPACMERR("unable to open %s\n", IPACM_TCP_FULL_FILE_NAME);
+		goto fail;
+	}
+
+
+	if (fscanf(tcp_fd, "%d", &tcp_timeout) != 1) {
+		IPACMERR("Error reading tcp timeout\n");
+	}
+	IPACMDBG_H("tcp timeout value: %d\n", tcp_timeout);
+
+fail:
+	if (udp_fd) {
+		fclose(udp_fd);
+	}
+	if (tcp_fd) {
+		fclose(tcp_fd);
+	}
+
+	return;
+}
diff --git a/ipacm/src/IPACM_EvtDispatcher.cpp b/ipacm/src/IPACM_EvtDispatcher.cpp
new file mode 100644
index 0000000..edb5901
--- /dev/null
+++ b/ipacm/src/IPACM_EvtDispatcher.cpp
@@ -0,0 +1,214 @@
+/* 
+Copyright (c) 2013-2016, 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_EvtDispatcher.cpp
+
+	@brief
+	This file implements the IPAM event dispatcher functionality
+
+	@Author
+
+*/
+#include <string.h>
+#include <pthread.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Neighbor.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+
+
+extern pthread_mutex_t mutex;
+extern pthread_cond_t  cond_var;
+
+cmd_evts *IPACM_EvtDispatcher::head = NULL;
+extern uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
+
+int IPACM_EvtDispatcher::PostEvt
+(
+	 ipacm_cmd_q_data *data
+)
+{
+	Message *item = NULL;
+	MessageQueue *MsgQueue = NULL;
+
+	if(data->event < IPA_EXTERNAL_EVENT_MAX)
+	{
+		IPACMDBG("Insert event into external queue.\n");
+		MsgQueue = MessageQueue::getInstanceExternal();
+	}
+	else
+	{
+		IPACMDBG("Insert event into internal queue.\n");
+		MsgQueue = MessageQueue::getInstanceInternal();
+	}
+	if(MsgQueue == NULL)
+	{
+		IPACMERR("unable to retrieve MsgQueue instance\n");
+		return IPACM_FAILURE;
+	}
+
+	item = new Message();
+	if(item == NULL)
+	{
+		IPACMERR("unable to create new message item\n");
+		return IPACM_FAILURE;
+	}
+
+	item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
+	memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));
+
+	if(pthread_mutex_lock(&mutex) != 0)
+	{
+		IPACMERR("unable to lock the mutex\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG("Enqueing item\n");
+	MsgQueue->enqueue(item);
+	IPACMDBG("Enqueued item %p\n", item);
+
+	if(pthread_cond_signal(&cond_var) != 0)
+	{
+		IPACMDBG("unable to lock the mutex\n");
+		/* Release the mutex before you return failure */
+		if(pthread_mutex_unlock(&mutex) != 0)
+		{
+			IPACMERR("unable to unlock the mutex\n");
+			return IPACM_FAILURE;
+		}
+		return IPACM_FAILURE;
+	}
+
+	if(pthread_mutex_unlock(&mutex) != 0)
+	{
+		IPACMERR("unable to unlock the mutex\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+void IPACM_EvtDispatcher::ProcessEvt(ipacm_cmd_q_data *data)
+{
+
+	cmd_evts *tmp = head, tmp1;
+
+	if(head == NULL)
+	{
+		IPACMDBG("Queue is empty\n");
+	}
+
+	while(tmp != NULL)
+	{
+	        memcpy(&tmp1, tmp, sizeof(tmp1));
+		if(data->event == tmp1.event)
+		{
+			ipacm_event_stats[data->event]++;
+			tmp1.obj->event_callback(data->event, data->evt_data);
+			IPACMDBG(" Find matched registered events\n");
+		}
+	        tmp = tmp1.next;
+	}
+
+	IPACMDBG(" Finished process events\n");
+			
+	if(data->evt_data != NULL)
+	{
+		IPACMDBG("free the event:%d data: %p\n", data->event, data->evt_data);
+		free(data->evt_data);
+	}
+	return;
+}
+
+int IPACM_EvtDispatcher::registr(ipa_cm_event_id event, IPACM_Listener *obj)
+{
+	cmd_evts *tmp = head,*nw;
+
+	nw = (cmd_evts *)malloc(sizeof(cmd_evts));
+	if(nw != NULL)
+	{
+		nw->event = event;
+		nw->obj = obj;
+		nw->next = NULL;
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	if(head == NULL)
+	{
+		head = nw;
+	}
+	else
+	{
+		while(tmp->next)
+		{
+			tmp = tmp->next;
+		}
+		tmp->next = nw;
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_EvtDispatcher::deregistr(IPACM_Listener *param)
+{
+	cmd_evts *tmp = head,*tmp1,*prev = head;
+
+	while(tmp != NULL)
+	{
+		if(tmp->obj == param)
+		{
+			tmp1 = tmp;
+			if(tmp == head)
+			{
+				head = head->next;
+			}
+			else if(tmp->next == NULL)
+			{
+				prev->next = NULL;
+			}
+			else
+			{
+				prev->next = tmp->next;
+			}
+
+			tmp = tmp->next;
+			free(tmp1);
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
new file mode 100644
index 0000000..22eb19c
--- /dev/null
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -0,0 +1,536 @@
+/*
+Copyright (c) 2013-2016, 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_Filtering.cpp
+
+	@brief
+	This file implements the IPACM filtering functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Filtering.h"
+#include <IPACM_Log.h>
+#include "IPACM_Defs.h"
+
+
+const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Filtering::IPACM_Filtering()
+{
+	fd = open(DEVICE_NAME, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+IPACM_Filtering::~IPACM_Filtering()
+{
+	close(fd);
+}
+
+bool IPACM_Filtering::DeviceNodeIsOpened()
+{
+	return fd;
+}
+
+bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
+{
+	int retval = 0;
+
+	IPACMDBG("Printing filter add attributes\n");
+	IPACMDBG("ip type: %d\n", ruleTable->ip);
+	IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+	IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
+	IPACMDBG("commit value: %d\n", ruleTable->commit);
+	for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", cnt,
+				ruleTable->rules[cnt].rule.attrib.attrib_mask);
+	}
+
+	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
+	if (retval != 0)
+	{
+		IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+		PERROR("unable to add filter rule:");
+
+		for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
+		{
+			if (ruleTable->rules[cnt].status != 0)
+			{
+				IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+								 cnt, ruleTable->rules[cnt].status);
+			}
+		}
+		return false;
+	}
+
+	for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+	{
+		if(ruleTable->rules[cnt].status != 0)
+		{
+			IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+							 cnt, ruleTable->rules[cnt].status);
+		}
+	}
+
+	IPACMDBG("Added Filtering rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Filtering::AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable)
+{
+#ifdef FEATURE_IPA_V3
+	int retval = 0;
+
+	IPACMDBG("Printing filter add attributes\n");
+	IPACMDBG("ip type: %d\n", ruleTable->ip);
+	IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+	IPACMDBG("End point: %d\n", ruleTable->ep);
+	IPACMDBG("commit value: %d\n", ruleTable->commit);
+
+	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_AFTER, ruleTable);
+
+	for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+	{
+		if(ruleTable->rules[cnt].status != 0)
+		{
+			IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+							 cnt, ruleTable->rules[cnt].status);
+		}
+	}
+
+	if (retval != 0)
+	{
+		IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+		return false;
+	}
+	IPACMDBG("Added Filtering rule %p\n", ruleTable);
+#endif
+	return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
+	if (retval != 0)
+	{
+		IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
+		return false;
+	}
+
+	IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval != 0)
+	{
+		IPACMERR("failed committing Filtering rules.\n");
+		return false;
+	}
+
+	IPACMDBG("Committed Filtering rules to IPA HW.\n");
+	return true;
+}
+
+bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
+	retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval)
+	{
+		IPACMERR("failed resetting Filtering block.\n");
+		return false;
+	}
+
+	IPACMDBG("Reset command issued to IPA Filtering block.\n");
+	return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringHdls
+(
+	 uint32_t *flt_rule_hdls,
+	 ipa_ip_type ip,
+	 uint8_t num_rules
+)
+{
+	struct ipa_ioc_del_flt_rule *flt_rule;
+	bool res = true;
+	int len = 0, cnt = 0;
+        const uint8_t UNIT_RULES = 1;
+
+	len = (sizeof(struct ipa_ioc_del_flt_rule)) + (UNIT_RULES * sizeof(struct ipa_flt_rule_del));
+	flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
+	if (flt_rule == NULL)
+	{
+		IPACMERR("unable to allocate memory for del filter rule\n");
+		return false;
+	}
+
+	for (cnt = 0; cnt < num_rules; cnt++)
+	{
+	    memset(flt_rule, 0, len);
+	    flt_rule->commit = 1;
+	    flt_rule->num_hdls = UNIT_RULES;
+	    flt_rule->ip = ip;
+
+	    if (flt_rule_hdls[cnt] == 0)
+	    {
+		   IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
+	    }
+            else
+	    {
+
+		   flt_rule->hdl[0].status = -1;
+		   flt_rule->hdl[0].hdl = flt_rule_hdls[cnt];
+		   IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
+
+	           if (DeleteFilteringRule(flt_rule) == false)
+	           {
+		        PERROR("Filter rule deletion failed!\n");
+		        res = false;
+		        goto fail;
+	           }
+		   else
+	           {
+
+		        if (flt_rule->hdl[0].status != 0)
+		        {
+			     IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
+		        					 flt_rule->hdl[0].hdl, flt_rule->hdl[0].status);
+			     res = false;
+			     goto fail;
+		        }
+		   }
+	    }
+	}
+
+fail:
+	free(flt_rule);
+
+	return res;
+}
+
+bool IPACM_Filtering::AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id)
+{
+	int ret = 0, cnt, num_rules = 0, pos = 0;
+	ipa_install_fltr_rule_req_msg_v01 qmi_rule_msg;
+#ifdef FEATURE_IPA_V3
+	ipa_install_fltr_rule_req_ex_msg_v01 qmi_rule_ex_msg;
+#endif
+
+	int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+	if(fd_wwan_ioctl < 0)
+	{
+		IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+		return false;
+	}
+
+	if(rule_table_v4 != NULL)
+	{
+		num_rules += rule_table_v4->num_rules;
+		IPACMDBG_H("Get %d WAN DL IPv4 filtering rules.\n", rule_table_v4->num_rules);
+	}
+	if(rule_table_v6 != NULL)
+	{
+		num_rules += rule_table_v6->num_rules;
+		IPACMDBG_H("Get %d WAN DL IPv6 filtering rules.\n", rule_table_v6->num_rules);
+	}
+
+	/* if it is not IPA v3, use old QMI format */
+#ifndef FEATURE_IPA_V3
+	if(num_rules > QMI_IPA_MAX_FILTERS_V01)
+	{
+		IPACMERR("The number of filtering rules exceed limit.\n");
+		close(fd_wwan_ioctl);
+		return false;
+	}
+	else
+	{
+		memset(&qmi_rule_msg, 0, sizeof(qmi_rule_msg));
+
+		if (num_rules > 0)
+		{
+			qmi_rule_msg.filter_spec_list_valid = true;
+		}
+		else
+		{
+			qmi_rule_msg.filter_spec_list_valid = false;
+		}
+
+		qmi_rule_msg.filter_spec_list_len = num_rules;
+		qmi_rule_msg.source_pipe_index_valid = 0;
+
+		IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
+
+		if(rule_table_v4 != NULL)
+		{
+			for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
+			{
+				if (pos < QMI_IPA_MAX_FILTERS_V01)
+				{
+					qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+					qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+					qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+					memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+						&rule_table_v4->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+					pos++;
+				}
+				else
+				{
+					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
+				}
+			}
+		}
+
+		if(rule_table_v6 != NULL)
+		{
+			for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
+			{
+				if (pos < QMI_IPA_MAX_FILTERS_V01)
+				{
+					qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+					qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+					qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+					memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+						&rule_table_v6->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+					pos++;
+				}
+				else
+				{
+					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
+				}
+			}
+		}
+
+		ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE, &qmi_rule_msg);
+		if (ret != 0)
+		{
+			IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_msg, ret);
+			close(fd_wwan_ioctl);
+			return false;
+		}
+	}
+	/* if it is IPA v3, use new QMI format */
+#else
+	if(num_rules > QMI_IPA_MAX_FILTERS_EX_V01)
+	{
+		IPACMERR("The number of filtering rules exceed limit.\n");
+		close(fd_wwan_ioctl);
+		return false;
+	}
+	else
+	{
+		memset(&qmi_rule_ex_msg, 0, sizeof(qmi_rule_ex_msg));
+
+		if (num_rules > 0)
+		{
+			qmi_rule_ex_msg.filter_spec_ex_list_valid = true;
+		}
+		else
+		{
+			qmi_rule_ex_msg.filter_spec_ex_list_valid = false;
+		}
+		qmi_rule_ex_msg.filter_spec_ex_list_len = num_rules;
+		qmi_rule_ex_msg.source_pipe_index_valid = 0;
+
+		IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
+
+		if(rule_table_v4 != NULL)
+		{
+			for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
+			{
+				if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
+				{
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v4->rules[cnt].rule.rule_id;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v4->rules[cnt].rule.hashable;
+					memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
+						&rule_table_v4->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+
+					pos++;
+				}
+				else
+				{
+					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
+				}
+			}
+		}
+
+		if(rule_table_v6 != NULL)
+		{
+			for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
+			{
+				if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
+				{
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v6->rules[cnt].rule.rule_id;
+					qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v6->rules[cnt].rule.hashable;
+					memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
+						&rule_table_v6->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+
+					pos++;
+				}
+				else
+				{
+					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
+				}
+			}
+		}
+
+		ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_EX, &qmi_rule_ex_msg);
+		if (ret != 0)
+		{
+			IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_ex_msg, ret);
+			close(fd_wwan_ioctl);
+			return false;
+		}
+	}
+#endif
+
+	close(fd_wwan_ioctl);
+	return true;
+}
+
+bool IPACM_Filtering::SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table)
+{
+	int ret = 0;
+	int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+	if(fd_wwan_ioctl < 0)
+	{
+		IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+		return false;
+	}
+
+	ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_INDEX, table);
+	if (ret != 0)
+	{
+		IPACMERR("Failed adding filtering rule index %p with ret %d\n", table, ret);
+		close(fd_wwan_ioctl);
+		return false;
+	}
+
+	IPACMDBG("Added Filtering rule index %p\n", table);
+	close(fd_wwan_ioctl);
+	return true;
+}
+
+ipa_filter_action_enum_v01 IPACM_Filtering::GetQmiFilterAction(ipa_flt_action action)
+{
+	switch(action)
+	{
+	case IPA_PASS_TO_ROUTING:
+		return QMI_IPA_FILTER_ACTION_ROUTING_V01;
+
+	case IPA_PASS_TO_SRC_NAT:
+		return QMI_IPA_FILTER_ACTION_SRC_NAT_V01;
+
+	case IPA_PASS_TO_DST_NAT:
+		return QMI_IPA_FILTER_ACTION_DST_NAT_V01;
+
+	case IPA_PASS_TO_EXCEPTION:
+		return QMI_IPA_FILTER_ACTION_EXCEPTION_V01;
+
+	default:
+		return IPA_FILTER_ACTION_ENUM_MAX_ENUM_VAL_V01;
+	}
+}
+
+bool IPACM_Filtering::ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable)
+{
+	int i, ret = 0;
+
+	IPACMDBG("Printing filtering add attributes\n");
+	IPACMDBG("IP type: %d Number of rules: %d commit value: %d\n", ruleTable->ip, ruleTable->num_rules, ruleTable->commit);
+
+	for (i=0; i<ruleTable->num_rules; i++)
+	{
+		IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", i, ruleTable->rules[i].rule.attrib.attrib_mask);
+	}
+
+	ret = ioctl(fd, IPA_IOC_MDFY_FLT_RULE, ruleTable);
+	if (ret != 0)
+	{
+		IPACMERR("Failed modifying filtering rule %p\n", ruleTable);
+
+		for (i = 0; i < ruleTable->num_rules; i++)
+		{
+			if (ruleTable->rules[i].status != 0)
+			{
+				IPACMERR("Modifying filter rule %d failed\n", i);
+			}
+		}
+		return false;
+	}
+
+	IPACMDBG("Modified filtering rule %p\n", ruleTable);
+	return true;
+}
+
diff --git a/ipacm/src/IPACM_Header.cpp b/ipacm/src/IPACM_Header.cpp
new file mode 100644
index 0000000..c77c69c
--- /dev/null
+++ b/ipacm/src/IPACM_Header.cpp
@@ -0,0 +1,236 @@
+/*
+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 <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Header.h"
+#include "IPACM_Log.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//All interaction through the driver are made through this inode.
+static const char *DEVICE_NAME = "/dev/ipa";
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::IPACM_Header()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (-1 == m_fd)
+	{
+		IPACMERR("Failed to open %s in IPACM_Header test application constructor.\n", DEVICE_NAME);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::~IPACM_Header()
+{
+	if (-1 != m_fd)
+	{
+		close(m_fd);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeviceNodeIsOpened()
+{
+	return (-1 != m_fd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
+{
+	int nRetVal = 0;
+	//call the Driver ioctl in order to add header
+	nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
+{
+	int nRetVal = 0;
+	//call the Driver ioctl in order to remove header
+	nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR, pHeaderTableToDelete);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Commit()
+{
+	int nRetVal = 0;
+	nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Reset()
+{
+	int nRetVal = 0;
+
+	nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
+	nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
+	if (retval)
+	{
+		IPACMERR("IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n", pHeaderStruct, retval);
+		return false;
+	}
+
+	IPACMDBG("IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n");
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
+	if (retval)
+	{
+		IPACMERR("IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n", retval);
+		return false;
+	}
+
+	IPACMDBG("IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n");
+	return true;
+}
+
+bool IPACM_Header::DeleteHeaderHdl(uint32_t hdr_hdl)
+{
+	const uint8_t NUM_HDLS = 1;
+	struct ipa_ioc_del_hdr *pHeaderDescriptor = NULL;
+	struct ipa_hdr_del *hd_rule_entry;
+	int len = 0;
+	bool res = true;
+
+	if (hdr_hdl == 0)
+	{
+		IPACMERR("Invalid header handle passed. Ignoring it\n");
+		return false;
+	}
+
+	len = (sizeof(struct ipa_ioc_del_hdr)) + (NUM_HDLS * sizeof(struct ipa_hdr_del));
+	pHeaderDescriptor = (struct ipa_ioc_del_hdr *)malloc(len);
+	if (pHeaderDescriptor == NULL)
+	{
+		IPACMERR("Unable to allocate memory for del header\n");
+		return false;
+	}
+
+	memset(pHeaderDescriptor, 0, len);
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdls = NUM_HDLS;
+	hd_rule_entry = &pHeaderDescriptor->hdl[0];
+
+	hd_rule_entry->hdl = hdr_hdl;
+	hd_rule_entry->status = -1;
+
+	IPACMDBG("Deleting Header hdl:(%x)\n", hd_rule_entry->hdl);
+	if ((false == DeleteHeader(pHeaderDescriptor)) ||
+			(hd_rule_entry->status))
+	{
+	    IPACMERR("Header hdl:(%x) deletion failed!  status: %d\n", hd_rule_entry->hdl,hd_rule_entry->status);
+		res = false;
+		goto fail;
+	}
+
+	IPACMDBG_H("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
+
+fail:
+	free(pHeaderDescriptor);
+
+	return res;
+
+}
+
+bool IPACM_Header::AddHeaderProcCtx(struct ipa_ioc_add_hdr_proc_ctx* pHeader)
+{
+	int ret = 0;
+	//call the Driver ioctl to add header processing context
+	ret = ioctl(m_fd, IPA_IOC_ADD_HDR_PROC_CTX, pHeader);
+	return (ret == 0);
+}
+
+bool IPACM_Header::DeleteHeaderProcCtx(uint32_t hdl)
+{
+	int len, ret;
+	struct ipa_ioc_del_hdr_proc_ctx* pHeaderTable = NULL;
+
+	len = sizeof(struct ipa_ioc_del_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_del);
+	pHeaderTable = (struct ipa_ioc_del_hdr_proc_ctx*)malloc(len);
+	if(pHeaderTable == NULL)
+	{
+		IPACMERR("Failed to allocate buffer.\n");
+		return false;
+	}
+	memset(pHeaderTable, 0, len);
+
+	pHeaderTable->commit = 1;
+	pHeaderTable->num_hdls = 1;
+	pHeaderTable->hdl[0].hdl = hdl;
+
+	ret = ioctl(m_fd, IPA_IOC_DEL_HDR_PROC_CTX, pHeaderTable);
+	if(ret != 0)
+	{
+		IPACMERR("Failed to delete hdr proc ctx: return value %d, status %d\n",
+			ret, pHeaderTable->hdl[0].status);
+	}
+	free(pHeaderTable);
+	return (ret == 0);
+}
+
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
new file mode 100644
index 0000000..84132c9
--- /dev/null
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -0,0 +1,995 @@
+/*
+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.Z
+*/
+/*!
+  @file
+  IPACM_Iface.cpp
+
+  @brief
+  This file implements the basis Iface functionality.
+
+  @Author
+  Skylar Chang
+
+*/
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <IPACM_Netlink.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Wlan.h>
+#include <string.h>
+
+extern "C"
+{
+#include <ifaddrs.h>
+}
+
+
+const char *IPACM_Iface::DEVICE_NAME = "/dev/ipa";
+IPACM_Routing IPACM_Iface::m_routing;
+IPACM_Filtering IPACM_Iface::m_filtering;
+IPACM_Header IPACM_Iface::m_header;
+
+IPACM_Config *IPACM_Iface::ipacmcfg = IPACM_Config::GetInstance();
+
+IPACM_Iface::IPACM_Iface(int iface_index)
+{
+	ip_type = IPACM_IP_NULL; /* initially set invalid */
+	num_dft_rt_v6 = 0;
+	softwarerouting_act = false;
+	ipa_if_num = iface_index;
+	ipa_if_cate = IPACM_Iface::ipacmcfg->iface_table[iface_index].if_cat;
+
+	iface_query = NULL;
+	tx_prop = NULL;
+	rx_prop = NULL;
+
+	memcpy(dev_name,
+				 IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name,
+				 sizeof(IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name));
+
+	memset(dft_v4fl_rule_hdl, 0, sizeof(dft_v4fl_rule_hdl));
+	memset(dft_v6fl_rule_hdl, 0, sizeof(dft_v6fl_rule_hdl));
+
+	memset(dft_rt_rule_hdl, 0, sizeof(dft_rt_rule_hdl));
+	memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
+	memset(ipv6_addr, 0, sizeof(ipv6_addr));
+
+	query_iface_property();
+	IPACMDBG_H(" create iface-index(%d) constructor\n", ipa_if_num);
+	return;
+}
+
+/* software routing enable */
+int IPACM_Iface::handle_software_routing_enable(void)
+{
+
+	int res = IPACM_SUCCESS;
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("\n");
+	if (softwarerouting_act == true)
+	{
+		IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
+						     IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+		return IPACM_SUCCESS;
+	}
+
+	if(rx_prop == NULL)
+	{
+		IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+		 calloc(1,
+						sizeof(struct ipa_ioc_add_flt_rule) +
+						1 * sizeof(struct ipa_flt_rule_add)
+						);
+	if (!m_pFilteringTable)
+	{
+		IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	m_pFilteringTable->global = false;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+	/* Configuring Software-Routing Filtering Rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+	flt_rule_entry.at_rear = false;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+	flt_rule_entry.rule.hashable = true;
+#endif
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+	/* check iface is v4 or v6 or both*/
+//	if (ip_type == IPA_IP_MAX)
+//	{
+		/* handle v4 */
+		m_pFilteringTable->ip = IPA_IP_v4;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+		/* handle v6*/
+		m_pFilteringTable->ip = IPA_IP_v6;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		softwarerouting_act = true;
+#if 0
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4)
+		{
+			m_pFilteringTable->ip = IPA_IP_v4;
+		}
+		else
+		{
+			m_pFilteringTable->ip = IPA_IP_v6;
+		}
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, ip_type, 1);
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		if (ip_type == IPA_IP_v4)
+		{
+			software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		else
+		{
+			software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		softwarerouting_act = true;
+	}
+#endif
+
+fail:
+	free(m_pFilteringTable);
+
+	return res;
+}
+
+/* software routing disable */
+int IPACM_Iface::handle_software_routing_disable(void)
+{
+	int res = IPACM_SUCCESS;
+	ipa_ip_type ip;
+	uint32_t flt_hdl;
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if (softwarerouting_act == false)
+	{
+		IPACMDBG("already delete software_routing rule for (%s)iface ip-family %d\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+		return IPACM_SUCCESS;
+	}
+
+//	if (ip_type == IPA_IP_MAX)
+//	{
+		/* ipv4 case */
+		if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
+																				IPA_IP_v4, 1) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+
+		/* ipv6 case */
+		if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
+																				IPA_IP_v6, 1) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+		softwarerouting_act = false;
+#if 0
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4)
+		{
+			ip = IPA_IP_v4;
+		}
+		else
+		{
+			ip = IPA_IP_v6;
+		}
+
+
+		if (ip_type == IPA_IP_v4)
+		{
+			flt_hdl = software_routing_fl_rule_hdl[0];
+		}
+		else
+		{
+			flt_hdl = software_routing_fl_rule_hdl[1];
+		}
+
+		if (m_filtering.DeleteFilteringHdls(&flt_hdl, ip, 1) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, ip, 1);
+		softwarerouting_act = false;
+	}
+#endif
+
+fail:
+	return res;
+}
+
+/* Query ipa_interface_index by given linux interface_index */
+int IPACM_Iface::iface_ipa_index_query
+(
+	 int interface_index
+)
+{
+	int fd;
+	int link = INVALID_IFACE;
+	int i = 0;
+	struct ifreq ifr;
+
+
+	if(IPACM_Iface::ipacmcfg->iface_table == NULL)
+	{
+		IPACMERR("Iface table in IPACM_Config is not available.\n");
+		return link;
+	}
+
+	/* Search known linux interface-index and map to IPA interface-index*/
+	for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+	{
+		if (interface_index == IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index)
+		{
+			link = i;
+			IPACMDBG("Interface (%s) found: linux(%d) ipa(%d) \n",
+							 IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+							 IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index,
+							 link);
+			return link;
+			break;
+		}
+	}
+
+	/* Search/Configure linux interface-index and map it to IPA interface-index */
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface name socket create failed");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	ifr.ifr_ifindex = interface_index;
+	IPACMDBG_H("Interface index %d\n", interface_index);
+
+	if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		PERROR("call_ioctl_on_dev: ioctl failed:");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+	close(fd);
+
+	IPACMDBG_H("Received interface name %s\n", ifr.ifr_name);
+	for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+	{
+		if (strncmp(ifr.ifr_name,
+								IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+								sizeof(IPACM_Iface::ipacmcfg->iface_table[i].iface_name)) == 0)
+		{
+			IPACMDBG_H("Interface (%s) linux(%d) mapped to ipa(%d) \n", ifr.ifr_name,
+							 IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index, i);
+
+			link = i;
+			IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index = interface_index;
+			break;
+		}
+	}
+
+	return link;
+}
+
+/* Query ipa_interface ipv4_addr by given linux interface_index */
+void IPACM_Iface::iface_addr_query
+(
+	 int interface_index
+)
+{
+	int fd;
+	struct ifreq ifr;
+	struct ifaddrs *myaddrs, *ifa;
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_data_addr *data_addr;
+	struct in_addr iface_ipv4;
+
+	/* use linux interface-index to find interface name */
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface name socket create failed");
+		return ;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	ifr.ifr_ifindex = interface_index;
+	IPACMDBG_H("Interface index %d\n", interface_index);
+
+	if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		PERROR("call_ioctl_on_dev: ioctl failed:");
+		close(fd);
+		return ;
+	}
+	IPACMDBG_H("Interface index %d name: %s\n", interface_index,ifr.ifr_name);
+	close(fd);
+
+	/* query ipv4/v6 address */
+    if(getifaddrs(&myaddrs) != 0)
+	{
+        IPACMERR("getifaddrs");
+		return ;
+	}
+
+    for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
+    {
+        if (ifa->ifa_addr == NULL)
+            continue;
+        if (!(ifa->ifa_flags & IFF_UP))
+            continue;
+
+		if(strcmp(ifr.ifr_name,ifa->ifa_name) == 0) // find current iface
+		{
+			IPACMDBG_H("Internal post new_addr event for iface %s\n", ifa->ifa_name);
+			switch (ifa->ifa_addr->sa_family)
+			{
+				case AF_INET:
+				{
+					struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
+					IPACMDBG_H("ipv4 address %s\n",inet_ntoa(s4->sin_addr));
+					iface_ipv4 = s4->sin_addr;
+					/* post new_addr event to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						freeifaddrs(myaddrs);
+						return ;
+					}
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->if_index = interface_index;
+					data_addr->ipv4_addr = 	iface_ipv4.s_addr;
+					data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+					IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+						data_addr->if_index,
+						data_addr->ipv4_addr);
+
+					evt_data.event = IPA_ADDR_ADD_EVENT;
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					break;
+				}
+
+				case AF_INET6:
+				{
+					struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+					/* post new_addr event to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						freeifaddrs(myaddrs);
+						return ;
+					}
+					data_addr->iptype = IPA_IP_v6;
+					data_addr->if_index = interface_index;
+					memcpy(data_addr->ipv6_addr,
+									&s6->sin6_addr,
+									sizeof(data_addr->ipv6_addr));
+					data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+					data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+					data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+					data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+					IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv6 addr:0x%x:%x:%x:%x\n",
+							data_addr->if_index,
+							data_addr->ipv6_addr[0], data_addr->ipv6_addr[1], data_addr->ipv6_addr[2], data_addr->ipv6_addr[3]);
+
+					evt_data.event = IPA_ADDR_ADD_EVENT;
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					break;
+				}
+
+				default:
+					continue;
+			}
+		}
+	}
+    freeifaddrs(myaddrs);
+	return ;
+}
+
+/*Query the IPA endpoint property */
+int IPACM_Iface::query_iface_property(void)
+{
+	int res = IPACM_SUCCESS, fd = 0;
+	uint32_t cnt=0;
+
+	fd = open(DEVICE_NAME, O_RDWR);
+	IPACMDBG("iface query-property \n");
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+	iface_query = (struct ipa_ioc_query_intf *)
+		 calloc(1, sizeof(struct ipa_ioc_query_intf));
+	if(iface_query == NULL)
+	{
+		IPACMERR("Unable to allocate iface_query memory.\n");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("iface name %s\n", dev_name);
+	memcpy(iface_query->name, dev_name, sizeof(dev_name));
+
+	if (ioctl(fd, IPA_IOC_QUERY_INTF, iface_query) < 0)
+	{
+		PERROR("ioctl IPA_IOC_QUERY_INTF failed\n");
+		/* iface_query memory will free when iface-down*/
+		res = IPACM_FAILURE;
+	}
+
+	if(iface_query->num_tx_props > 0)
+	{
+		tx_prop = (struct ipa_ioc_query_intf_tx_props *)
+			 calloc(1, sizeof(struct ipa_ioc_query_intf_tx_props) +
+							iface_query->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop));
+		if(tx_prop == NULL)
+		{
+			IPACMERR("Unable to allocate tx_prop memory.\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		memcpy(tx_prop->name, dev_name, sizeof(tx_prop->name));
+		tx_prop->num_tx_props = iface_query->num_tx_props;
+
+		if (ioctl(fd, IPA_IOC_QUERY_INTF_TX_PROPS, tx_prop) < 0)
+		{
+			PERROR("ioctl IPA_IOC_QUERY_INTF_TX_PROPS failed\n");
+			/* tx_prop memory will free when iface-down*/
+			res = IPACM_FAILURE;
+		}
+
+		if (res != IPACM_FAILURE)
+		{
+			for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
+			{
+				IPACMDBG_H("Tx(%d):attrib-mask:0x%x, ip-type: %d, dst_pipe: %d, alt_dst_pipe: %d, header: %s\n",
+						cnt, tx_prop->tx[cnt].attrib.attrib_mask,
+						tx_prop->tx[cnt].ip, tx_prop->tx[cnt].dst_pipe,
+						tx_prop->tx[cnt].alt_dst_pipe,
+						tx_prop->tx[cnt].hdr_name);
+
+				if (tx_prop->tx[cnt].dst_pipe == 0)
+				{
+					IPACMERR("Tx(%d): wrong tx property: dst_pipe: 0.\n", cnt);
+					close(fd);
+					return IPACM_FAILURE;
+				}
+				if (tx_prop->tx[cnt].alt_dst_pipe == 0 &&
+					((memcmp(dev_name, "wlan0", sizeof("wlan0")) == 0) ||
+					(memcmp(dev_name, "wlan1", sizeof("wlan1")) == 0)))
+				{
+					IPACMERR("Tx(%d): wrong tx property: alt_dst_pipe: 0. \n", cnt);
+					close(fd);
+					return IPACM_FAILURE;
+				}
+
+			}
+		}
+
+	}
+
+	if (iface_query->num_rx_props > 0)
+	{
+		rx_prop = (struct ipa_ioc_query_intf_rx_props *)
+			 calloc(1, sizeof(struct ipa_ioc_query_intf_rx_props) +
+							iface_query->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop));
+		if(rx_prop == NULL)
+		{
+			IPACMERR("Unable to allocate rx_prop memory.\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		memcpy(rx_prop->name, dev_name,
+				 sizeof(rx_prop->name));
+		rx_prop->num_rx_props = iface_query->num_rx_props;
+
+		if (ioctl(fd, IPA_IOC_QUERY_INTF_RX_PROPS, rx_prop) < 0)
+		{
+			PERROR("ioctl IPA_IOC_QUERY_INTF_RX_PROPS failed\n");
+			/* rx_prop memory will free when iface-down*/
+			res = IPACM_FAILURE;
+		}
+
+		if (res != IPACM_FAILURE)
+		{
+			for (cnt = 0; cnt < rx_prop->num_rx_props; cnt++)
+			{
+				IPACMDBG_H("Rx(%d):attrib-mask:0x%x, ip-type: %d, src_pipe: %d\n",
+								 cnt, rx_prop->rx[cnt].attrib.attrib_mask, rx_prop->rx[cnt].ip, rx_prop->rx[cnt].src_pipe);
+			}
+		}
+	}
+
+	/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
+	if (rx_prop != NULL || tx_prop != NULL)
+	{
+		IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+        IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+	}
+
+	close(fd);
+	return res;
+}
+
+/*Configure the initial filter rules */
+int IPACM_Iface::init_fl_rule(ipa_ip_type iptype)
+{
+
+	int res = IPACM_SUCCESS, len = 0;
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+  /* Adding this hack because WLAN may not registered for Rx-endpoint, other ifaces will always have*/
+	const char *dev_wlan0="wlan0";
+	const char *dev_wlan1="wlan1";
+	const char *dev_ecm0="ecm0";
+
+    /* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
+	if((IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== WAN_IF) || (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== EMBMS_IF))
+	{
+		IPACMDBG_H(" NOT add producer dependency on dev %s with registered rx-prop cat:%d \n", dev_name, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat);
+	}
+	else
+	{
+		if(rx_prop != NULL)
+		{
+			IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+			IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+			IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe],false);
+		}
+		else
+		{
+			/* only wlan may take software-path, not register Rx-property*/
+			if(strcmp(dev_name,dev_wlan0) == 0 || strcmp(dev_name,dev_wlan1) == 0)
+			{
+				IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+				IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_HSIC_PROD);
+				IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_HSIC_PROD,true);
+			}
+			if(strcmp(dev_name,dev_ecm0) == 0)
+			{
+				IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+				IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_USB_PROD);
+				IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_USB_PROD,true);
+			}
+		}
+	}
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	/* construct ipa_ioc_add_flt_rule with default filter rules */
+	if (iptype == IPA_IP_v4)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) +
+			 (IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!m_pFilteringTable)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+		/* Configuring Fragment Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = false;
+#endif
+		IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Broadcast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+			/* copy filter hdls */
+			for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
+			{
+				if (m_pFilteringTable->rules[i].status == 0)
+				{
+					dft_v4fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+					IPACMDBG_H("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
+				}
+				else
+				{
+					IPACMERR("Failed adding default v4 Filtering rule %d\n", i);
+				}
+			}
+		}
+	}
+	else
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) +
+			 (IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!m_pFilteringTable)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring fec0::/10 Reserved by IETF Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+#ifdef FEATURE_IPA_ANDROID
+		IPACMDBG_H("Add TCP ctrl rules: total num %d\n", IPV6_DEFAULT_FILTERTING_RULES);
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap = 0;
+
+		if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
+		{
+			flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+			flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+		}
+
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+		flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
+		flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+		flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+
+		/* add TCP FIN rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+		memcpy(&(m_pFilteringTable->rules[3]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* add TCP SYN rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+		memcpy(&(m_pFilteringTable->rules[4]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* add TCP RST rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+		memcpy(&(m_pFilteringTable->rules[5]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+#endif
+		if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+			/* copy filter hdls */
+			for (int i = 0;
+					 i < IPV6_DEFAULT_FILTERTING_RULES;
+					 i++)
+			{
+				if (m_pFilteringTable->rules[i].status == 0)
+				{
+					dft_v6fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+					IPACMDBG_H("Default v6 Filter Rule %d HDL:0x%x\n", i, dft_v6fl_rule_hdl[i]);
+				}
+				else
+				{
+					IPACMERR("Failing adding v6 default IPV6 rule %d\n", i);
+				}
+			}
+		}
+	}
+
+
+fail:
+	free(m_pFilteringTable);
+
+	return res;
+}
+
+/*  get ipa interface name */
+int IPACM_Iface::ipa_get_if_index
+(
+  char * if_name,
+  int * if_index
+)
+{
+  int fd;
+  struct ifreq ifr;
+
+  if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+  {
+    IPACMERR("get interface index socket create failed \n");
+    return IPACM_FAILURE;
+  }
+
+  memset(&ifr, 0, sizeof(struct ifreq));
+  (void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+  IPACMDBG_H("interface name (%s)\n", if_name);
+
+  if (ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
+  {
+    IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
+    close(fd);
+    return IPACM_FAILURE;
+  }
+
+  *if_index = ifr.ifr_ifindex;
+  IPACMDBG_H("Interface index %d\n", *if_index);
+  close(fd);
+  return IPACM_SUCCESS;
+}
+
+void IPACM_Iface::config_ip_type(ipa_ip_type iptype)
+{
+	/* update the iface ip-type to be IPA_IP_v4, IPA_IP_v6 or both*/
+	if (iptype == IPA_IP_v4)
+	{
+		if ((ip_type == IPA_IP_v4) || (ip_type == IPA_IP_MAX))
+		{
+			IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+			return;
+		}
+
+		if (ip_type == IPA_IP_v6)
+		{
+			ip_type = IPA_IP_MAX;
+		}
+		else
+		{
+			ip_type = IPA_IP_v4;
+		}
+		IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+	}
+	else
+	{
+		if ((ip_type == IPA_IP_v6) || (ip_type == IPA_IP_MAX))
+		{
+			IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+			return;
+		}
+
+		if (ip_type == IPA_IP_v4)
+		{
+			ip_type = IPA_IP_MAX;
+		}
+		else
+		{
+			ip_type = IPA_IP_v6;
+		}
+
+		IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+	}
+
+	return;
+}
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
new file mode 100644
index 0000000..a142553
--- /dev/null
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -0,0 +1,565 @@
+/*
+Copyright (c) 2013-2016, 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_IfaceManager.cpp
+
+	@brief
+	This file implements the IPAM iface_manager functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <IPACM_IfaceManager.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Log.h>
+
+iface_instances *IPACM_IfaceManager::head = NULL;
+
+IPACM_IfaceManager::IPACM_IfaceManager()
+{
+	IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, this); 		// register for IPA_CFG_CHANGE event
+	IPACM_EvtDispatcher::registr(IPA_LINK_UP_EVENT, this);
+	IPACM_EvtDispatcher::registr(IPA_WLAN_AP_LINK_UP_EVENT, this);  // register for wlan AP-iface
+	IPACM_EvtDispatcher::registr(IPA_WLAN_STA_LINK_UP_EVENT, this); // register for wlan STA-iface
+#ifndef FEATURE_IPA_ANDROID
+	/* only MDM targets support device on bridge mode */
+	IPACM_EvtDispatcher::registr(IPA_BRIDGE_LINK_UP_EVENT, this); 	// register for IPA_BRIDGE_LINK_UP_EVENT event
+#endif /* not defined(FEATURE_IPA_ANDROID)*/
+	IPACM_EvtDispatcher::registr(IPA_USB_LINK_UP_EVENT, this); // register for USB-iface
+	IPACM_EvtDispatcher::registr(IPA_WAN_EMBMS_LINK_UP_EVENT, this);  // register for wan eMBMS-iface
+	return;
+}
+
+void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param)
+{
+	int ipa_interface_index;
+	ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
+	ipacm_event_data_mac *StaData = (ipacm_event_data_mac *)param;
+	ipacm_event_data_all *data_all = (ipacm_event_data_all *)param;
+	ipacm_ifacemgr_data ifmgr_data = {0};
+
+	switch(event)
+	{
+		case IPA_CFG_CHANGE_EVENT:
+				IPACMDBG_H(" RESET IPACM_cfg \n");
+				IPACM_Iface::ipacmcfg->Init();
+			break;
+		case IPA_BRIDGE_LINK_UP_EVENT:
+			IPACMDBG_H(" Save the bridge0 mac info in IPACM_cfg \n");
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_BRIDGE_LINK_UP_EVENT: not supported iface id: %d\n", data_all->if_index);
+				break;
+			}
+			/* check if iface is bridge interface*/
+			if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+			{
+				IPACM_Iface::ipacmcfg->ipa_bridge_enable = true;
+				memcpy(IPACM_Iface::ipacmcfg->bridge_mac,
+								data_all->mac_addr,
+								sizeof(IPACM_Iface::ipacmcfg->bridge_mac));
+				IPACMDBG_H("cached bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+						 IPACM_Iface::ipacmcfg->bridge_mac[0], IPACM_Iface::ipacmcfg->bridge_mac[1], IPACM_Iface::ipacmcfg->bridge_mac[2],
+						 IPACM_Iface::ipacmcfg->bridge_mac[3], IPACM_Iface::ipacmcfg->bridge_mac[4], IPACM_Iface::ipacmcfg->bridge_mac[5]);
+			}
+			break;
+		case IPA_LINK_UP_EVENT:
+			IPACMDBG_H("Recieved IPA_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
+			/* LTE-backhaul */
+			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == EMBMS_IF)
+			{
+				IPACMDBG("WAN-EMBMS (%s) link already up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+			}
+			else if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+			{
+				IPACMDBG_H("WAN-LTE (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+				ifmgr_data.if_index = evt_data->if_index;
+				ifmgr_data.if_type = Q6_WAN;
+				create_iface_instance(&ifmgr_data);
+			}
+			break;
+
+		case IPA_USB_LINK_UP_EVENT:
+			IPACMDBG_H("Recieved IPA_USB_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_USB_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
+			/* check if it's WAN_IF */
+			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+			{
+				/* usb-backhaul using sta_mode ECM_WAN*/
+				IPACMDBG_H("WAN-usb (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, evt_data->if_index);
+				ifmgr_data.if_index = evt_data->if_index;
+				ifmgr_data.if_type = ECM_WAN;
+				create_iface_instance(&ifmgr_data);
+			}
+			else
+			{
+				ifmgr_data.if_index = evt_data->if_index;
+				ifmgr_data.if_type = Q6_WAN;
+				create_iface_instance(&ifmgr_data);
+			}
+			break;
+
+		case IPA_WLAN_AP_LINK_UP_EVENT:
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_AP_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
+			/* change iface category from unknown to WLAN_IF */
+			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
+			{
+				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WLAN_IF;
+				IPACMDBG_H("WLAN AP (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+				ifmgr_data.if_index = evt_data->if_index;
+				ifmgr_data.if_type = Q6_WAN;
+				create_iface_instance(&ifmgr_data);
+			}
+			else
+			{
+				IPACMDBG_H("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+			}
+			break;
+
+		case IPA_WLAN_STA_LINK_UP_EVENT:
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(StaData->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_STA_LINK_UP_EVENT: not supported iface id: %d\n", StaData->if_index);
+				break;
+			}
+			/* change iface category from unknown to WAN_IF */
+			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
+			{
+				/* wlan-backhaul using sta_mode WLAN_WAN */
+				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WAN_IF;
+				IPACMDBG_H("WLAN STA (%s) link up, iface: %d: \n",
+				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, StaData->if_index);
+
+				ifmgr_data.if_index = StaData->if_index;
+				ifmgr_data.if_type = WLAN_WAN;
+				memcpy(ifmgr_data.mac_addr, StaData->mac_addr, sizeof(ifmgr_data.mac_addr));
+				create_iface_instance(&ifmgr_data);
+			}
+			else
+			{
+				IPACMDBG_H("iface %s already up and act as %d mode: \n",
+				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
+						IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+			}
+			break;
+
+		/* Add new instance open for eMBMS iface and wan iface */
+		case IPA_WAN_EMBMS_LINK_UP_EVENT:
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WAN_EMBMS_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
+			/* change iface category from unknown to EMBMS_IF */
+			if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
+			{
+				IPACMDBG(" ODU-mode enable or not (%d) \n",IPACM_Iface::ipacmcfg->ipacm_odu_enable);
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+				{
+					IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
+					IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+					ifmgr_data.if_index = StaData->if_index;
+					ifmgr_data.if_type = Q6_WAN;
+					create_iface_instance(&ifmgr_data);
+				}
+				else
+				{
+					IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+				}
+			}
+			break;
+
+		default:
+			break;
+	}
+	return;
+}
+
+int IPACM_IfaceManager::create_iface_instance(ipacm_ifacemgr_data *param)
+{
+	int if_index = param->if_index;
+	ipacm_wan_iface_type is_sta_mode = param->if_type;
+
+	int ipa_interface_index;
+	ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
+
+	if(ipa_interface_index == INVALID_IFACE)
+	{
+			IPACMDBG_H("Unhandled interface received, fid: %d\n",if_index);
+			return IPACM_SUCCESS;
+	}
+
+	/* check if duplicate instance*/
+	if(SearchInstance(ipa_interface_index) == IPA_INSTANCE_NOT_FOUND)
+	{
+		/* IPA_INSTANCE_NOT_FOUND */
+		switch(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat)
+		{
+
+		case LAN_IF:
+			{
+				IPACMDBG_H("Creating Lan interface\n");
+				IPACM_Lan *lan = new IPACM_Lan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, lan);
+				//IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, lan);
+				//IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, lan);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, lan);
+#ifdef FEATURE_IPA_ANDROID
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, lan);
+#else
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, lan);
+#endif
+				IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, lan); 				// register for IPA_CFG_CHANGE event
+				IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, lan); 	// register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
+#ifdef FEATURE_IPA_ANDROID
+				IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, lan);
+#endif
+				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+				/* IPA_LAN_DELETE_SELF should be always last */
+				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, lan);
+				IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
+				registr(ipa_interface_index, lan);
+				/* solve the new_addr comes earlier issue */
+                                IPACM_Iface::iface_addr_query(if_index);
+			}
+			break;
+
+		case ETH_IF:
+			{
+				IPACMDBG_H("Creating ETH interface in router mode\n");
+				IPACM_Lan *ETH = new IPACM_Lan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, ETH);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, ETH);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, ETH);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, ETH);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, ETH);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, ETH);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, ETH);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, ETH);
+				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, ETH);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, ETH);
+				/* IPA_LAN_DELETE_SELF should be always last */
+				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, ETH);
+				IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", ETH->dev_name, ETH->ipa_if_num);
+				registr(ipa_interface_index, ETH);
+				/* solve the new_addr comes earlier issue */
+				IPACM_Iface::iface_addr_query(if_index);
+			}
+			break;
+
+		case ODU_IF:
+			{
+				if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true)
+				{
+					IPACMDBG_H("Creating ODU interface in router mode\n");
+					IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
+					IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
+					IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
+					IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, odu);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
+					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, odu);
+					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, odu);
+					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, odu);
+					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, odu);
+					IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, odu);
+					IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+					/* IPA_LAN_DELETE_SELF should be always last */
+					IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
+					IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
+					registr(ipa_interface_index, odu);
+					/* solve the new_addr comes earlier issue */
+					IPACM_Iface::iface_addr_query(if_index);
+				}
+				else
+				{
+					IPACMDBG_H("Creating ODU interface in bridge mode\n");
+					IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
+					IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
+					IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
+					IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+					/* IPA_LAN_DELETE_SELF should be always last */
+					IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
+					IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
+					registr(ipa_interface_index, odu);
+					/* solve the new_addr comes earlier issue */
+					IPACM_Iface::iface_addr_query(if_index);
+				}
+			}
+			break;
+
+		case WLAN_IF:
+			{
+				IPACMDBG_H("Creating WLan interface\n");
+				IPACM_Wlan *wl = new IPACM_Wlan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_DEL_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_POWER_SAVE_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_RECOVER_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, wl);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, wl);
+#ifdef FEATURE_IPA_ANDROID
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, wl);
+#else
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, wl);
+#endif
+				IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, wl); 	// register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
+#ifdef FEATURE_ETH_BRIDGE_LE
+				IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, wl);
+#endif
+				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, wl);
+#ifndef FEATURE_IPA_ANDROID
+				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
+#else
+				IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, wl);
+#endif
+				/* IPA_LAN_DELETE_SELF should be always last */
+				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, wl);
+				IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
+				registr(ipa_interface_index, wl);
+				/* solve the new_addr comes earlier issue */
+	            IPACM_Iface::iface_addr_query(if_index);
+			}
+			break;
+
+		case WAN_IF:
+			{
+				if((IPACM_Iface::ipacmcfg->ipacm_odu_enable == false) || (IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true))
+				{
+					IPACMDBG_H("Creating Wan interface\n");
+					IPACM_Wan *w;
+					if(is_sta_mode == WLAN_WAN)
+					{
+						w = new IPACM_Wan(ipa_interface_index, is_sta_mode, param->mac_addr);
+					}
+					else
+					{
+						w = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
+					}
+					IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
+#ifdef FEATURE_IPA_ANDROID
+					IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, w);
+					IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, w);
+					if(is_sta_mode == Q6_WAN)
+					{
+						IPACM_EvtDispatcher::registr(IPA_NETWORK_STATS_UPDATE_EVENT, w);
+					};
+#else/* defined(FEATURE_IPA_ANDROID) */
+					IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
+					IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
+#endif /* not defined(FEATURE_IPA_ANDROID)*/
+					IPACM_EvtDispatcher::registr(IPA_FIREWALL_CHANGE_EVENT, w);
+					IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, w);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, w);
+					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, w);
+					IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, w); 		// register for IPA_CFG_CHANGE event
+					IPACM_EvtDispatcher::registr(IPA_WAN_XLAT_CONNECT_EVENT, w);
+					if(is_sta_mode == WLAN_WAN)
+					{
+						IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, w); // for STA mode
+#ifndef FEATURE_IPA_ANDROID
+						IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, w);
+						IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, w);
+#endif
+					}
+					else
+					{
+						IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
+					}
+
+					IPACMDBG_H("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
+					registr(ipa_interface_index, w);
+					/* solve the new_addr comes earlier issue */
+					IPACM_Iface::iface_addr_query(if_index);
+				}
+			}
+			break;
+
+	    /* WAN-eMBMS instance */
+		case EMBMS_IF:
+			{
+				IPACMDBG("Creating Wan-eMBSM interface\n");
+				IPACM_Wan *embms = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, embms);
+				IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", embms->dev_name, embms->ipa_if_num);
+				registr(ipa_interface_index, embms);
+			}
+			break;
+
+		default:
+			IPACMDBG_H("Unhandled interface category received iface name: %s, category: %d\n",
+			            IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
+						       IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+			return IPACM_SUCCESS;
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::registr(int ipa_if_index, IPACM_Listener *obj)
+{
+	iface_instances *tmp = head,*nw;
+
+	nw = (iface_instances *)malloc(sizeof(iface_instances));
+	if(nw != NULL)
+	{
+		nw->ipa_if_index = ipa_if_index;
+		nw->obj = obj;
+		nw->next = NULL;
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	if(head == NULL)
+	{
+		head = nw;
+	}
+	else
+	{
+		while(tmp->next)
+		{
+			tmp = tmp->next;
+		}
+		tmp->next = nw;
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_IfaceManager::deregistr(IPACM_Listener *param)
+{
+	iface_instances *tmp = head,*tmp1,*prev = head;
+
+	while(tmp != NULL)
+	{
+		if(tmp->obj == param)
+		{
+			tmp1 = tmp;
+			if(tmp == head)
+			{
+				head = head->next;
+			}
+			else if(tmp->next == NULL)
+			{
+				prev->next = NULL;
+			}
+			else
+			{
+				prev->next = tmp->next;
+			}
+
+			tmp = tmp->next;
+			free(tmp1);
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
+{
+
+	iface_instances *tmp = head;
+
+	while(tmp != NULL)
+	{
+		if(ipa_if_index == tmp->ipa_if_index)
+		{
+			IPACMDBG_H("Find existed iface-instance name: %s\n",
+							 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+			return IPA_INSTANCE_FOUND;
+		}
+		tmp = tmp->next;
+	}
+
+	IPACMDBG_H("No existed iface-instance name: %s,\n",
+					 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+
+	return IPA_INSTANCE_NOT_FOUND;
+}
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
new file mode 100644
index 0000000..f8ed9d8
--- /dev/null
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -0,0 +1,4229 @@
+/*
+Copyright (c) 2013-2016, 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_Lan.cpp
+
+	@brief
+	This file implements the LAN iface functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "IPACM_Netlink.h"
+#include "IPACM_Lan.h"
+#include "IPACM_Wan.h"
+#include "IPACM_IfaceManager.h"
+#include "linux/rmnet_ipa_fd_ioctl.h"
+#include "linux/ipa_qmi_service_v01.h"
+#include "linux/msm_ipa.h"
+#include "IPACM_ConntrackListener.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+bool IPACM_Lan::odu_up = false;
+
+IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
+{
+	num_eth_client = 0;
+	header_name_count = 0;
+	ipv6_set = 0;
+	ipv4_header_set = false;
+	ipv6_header_set = false;
+	odu_route_rule_v4_hdl = NULL;
+	odu_route_rule_v6_hdl = NULL;
+	eth_client = NULL;
+	int i, m_fd_odu, ret = IPACM_SUCCESS;
+
+	Nat_App = NatApp::GetInstance();
+	if (Nat_App == NULL)
+	{
+		IPACMERR("unable to get Nat App instance \n");
+		return;
+	}
+
+	/* support eth multiple clients */
+	if(iface_query != NULL)
+	{
+		if(ipa_if_cate != WLAN_IF)
+		{
+			eth_client_len = (sizeof(ipa_eth_client)) + (iface_query->num_tx_props * sizeof(eth_client_rt_hdl));
+			eth_client = (ipa_eth_client *)calloc(IPA_MAX_NUM_ETH_CLIENTS, eth_client_len);
+			if (eth_client == NULL)
+			{
+				IPACMERR("unable to allocate memory\n");
+				return;
+			}
+		}
+
+		IPACMDBG_H(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d \n", ipa_if_num,
+					 iface_query->num_tx_props, iface_query->num_rx_props);
+
+		/* ODU routing table initilization */
+		if(ipa_if_cate == ODU_IF)
+		{
+			odu_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+			odu_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+			if ((odu_route_rule_v4_hdl == NULL) || (odu_route_rule_v6_hdl == NULL))
+			{
+				IPACMERR("unable to allocate memory\n");
+				return;
+			}
+		}
+	}
+
+	num_wan_ul_fl_rule_v4 = 0;
+	num_wan_ul_fl_rule_v6 = 0;
+
+	memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+	memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+
+	is_active = true;
+	memset(ipv4_icmp_flt_rule_hdl, 0, NUM_IPV4_ICMP_FLT_RULE * sizeof(uint32_t));
+
+	is_mode_switch = false;
+	if_ipv4_subnet =0;
+	memset(private_fl_rule_hdl, 0, IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(uint32_t));
+	memset(ipv6_prefix_flt_rule_hdl, 0, NUM_IPV6_PREFIX_FLT_RULE * sizeof(uint32_t));
+	memset(ipv6_icmp_flt_rule_hdl, 0, NUM_IPV6_ICMP_FLT_RULE * sizeof(uint32_t));
+	modem_ul_v4_set = false;
+	modem_ul_v6_set = false;
+	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+
+	/* ODU routing table initilization */
+	if(ipa_if_cate == ODU_IF)
+	{
+		/* only do one time ioctl to odu-driver to infrom in router or bridge mode*/
+		if (IPACM_Lan::odu_up != true)
+		{
+				m_fd_odu = open(IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU, O_RDWR);
+				if (0 == m_fd_odu)
+				{
+					IPACMERR("Failed opening %s.\n", IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU);
+					return ;
+				}
+
+				if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true)
+				{
+					ret = ioctl(m_fd_odu, ODU_BRIDGE_IOC_SET_MODE, ODU_BRIDGE_MODE_ROUTER);
+					IPACM_Iface::ipacmcfg->ipacm_odu_enable = true;
+				}
+				else
+				{
+					ret = ioctl(m_fd_odu, ODU_BRIDGE_IOC_SET_MODE, ODU_BRIDGE_MODE_BRIDGE);
+					IPACM_Iface::ipacmcfg->ipacm_odu_enable = true;
+				}
+
+				if (ret)
+				{
+					IPACMERR("Failed tell odu-driver the mode\n");
+				}
+				IPACMDBG("Tell odu-driver in router-mode(%d)\n", IPACM_Iface::ipacmcfg->ipacm_odu_router_mode);
+				IPACMDBG_H("odu is up: odu-driver in router-mode(%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_router_mode);
+				close(m_fd_odu);
+				IPACM_Lan::odu_up = true;
+		}
+	}
+
+	each_client_rt_rule_count[IPA_IP_v4] = 0;
+	each_client_rt_rule_count[IPA_IP_v6] = 0;
+	if(iface_query != NULL && tx_prop != NULL)
+	{
+		for(i=0; i<iface_query->num_tx_props; i++)
+			each_client_rt_rule_count[tx_prop->tx[i].ip]++;
+	}
+	IPACMDBG_H("Need to add %d IPv4 and %d IPv6 routing rules for eth bridge for each client.\n", each_client_rt_rule_count[IPA_IP_v4], each_client_rt_rule_count[IPA_IP_v6]);
+
+#ifdef FEATURE_IPA_ANDROID
+	/* set the IPA-client pipe enum */
+	if(ipa_if_cate == LAN_IF)
+	{
+		handle_tethering_client(false, IPACM_CLIENT_USB);
+	}
+#endif
+	return;
+}
+
+IPACM_Lan::~IPACM_Lan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+
+/* LAN-iface's callback function */
+void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
+{
+	if(is_active == false && event != IPA_LAN_DELETE_SELF)
+	{
+		IPACMDBG_H("The interface is no longer active, return.\n");
+		return;
+	}
+
+	int ipa_interface_index;
+	ipacm_ext_prop* ext_prop;
+	ipacm_event_iface_up* data_wan;
+	ipacm_event_iface_up_tehter* data_wan_tether;
+
+	switch (event)
+	{
+	case IPA_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_LINK_DOWN_EVENT\n");
+				handle_down_evt();
+				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+				return;
+			}
+		}
+		break;
+
+	case IPA_CFG_CHANGE_EVENT:
+		{
+			if ( IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate)
+			{
+				IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category changed\n");
+				/* delete previous instance */
+				handle_down_evt();
+				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+				is_mode_switch = true; // need post internal usb-link up event
+				return;
+			}
+			/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
+			if (rx_prop != NULL || tx_prop != NULL)
+			{
+				IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+				IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+			}
+		}
+		break;
+
+	case IPA_PRIVATE_SUBNET_CHANGE_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			/* internel event: data->if_index is ipa_if_index */
+			if (data->if_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from itself posting, ignore\n");
+				return;
+			}
+			else
+			{
+				IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from other LAN iface \n");
+#ifdef FEATURE_IPA_ANDROID
+				handle_private_subnet_android(IPA_IP_v4);
+#endif
+				IPACMDBG_H(" delete old private subnet rules, use new sets \n");
+				return;
+			}
+		}
+		break;
+
+	case IPA_LAN_DELETE_SELF:
+	{
+		ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+		if(data->if_index == ipa_if_num)
+		{
+			IPACMDBG_H("Received IPA_LAN_DELETE_SELF event.\n");
+			IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+			/* posting link-up event for cradle use-case */
+			if(is_mode_switch)
+			{
+				IPACMDBG_H("Posting IPA_USB_LINK_UP_EVENT event for (%s)\n", dev_name);
+				ipacm_cmd_q_data evt_data;
+				memset(&evt_data, 0, sizeof(evt_data));
+
+				ipacm_event_data_fid *data_fid = NULL;
+				data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+				if(data_fid == NULL)
+				{
+					IPACMERR("unable to allocate memory for IPA_USB_LINK_UP_EVENT data_fid\n");
+					return;
+				}
+				if(IPACM_Iface::ipa_get_if_index(dev_name, &(data_fid->if_index)))
+				{
+					IPACMERR("Error while getting interface index for %s device", dev_name);
+				}
+				evt_data.event = IPA_USB_LINK_UP_EVENT;
+				evt_data.evt_data = data_fid;
+				//IPACMDBG_H("Posting event:%d\n", evt_data.event);
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+			}
+#ifndef FEATURE_IPA_ANDROID
+			if(rx_prop != NULL)
+			{
+				if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4) != 0)
+				{
+					IPACMDBG_DMESG("### WARNING ### num ipv4 flt rules on client %d is not expected: %d expected value: 0",
+						rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4));
+				}
+				if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6) != 0)
+				{
+					IPACMDBG_DMESG("### WARNING ### num ipv6 flt rules on client %d is not expected: %d expected value: 0",
+						rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6));
+				}
+			}
+#endif
+			delete this;
+		}
+		break;
+	}
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+					 (data->iptype == IPA_IP_v6 &&
+						data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+					  data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+			{
+				IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+				return;
+			}
+
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_ADDR_ADD_EVENT\n");
+
+				/* only call ioctl for ODU iface with bridge mode */
+				if(IPACM_Iface::ipacmcfg->ipacm_odu_enable == true && IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false
+						&& ipa_if_cate == ODU_IF)
+				{
+					if((data->iptype == IPA_IP_v6) && (num_dft_rt_v6 == 0))
+					{
+						handle_addr_evt_odu_bridge(data);
+					}
+#ifdef FEATURE_IPA_ANDROID
+					add_dummy_private_subnet_flt_rule(data->iptype);
+					handle_private_subnet_android(data->iptype);
+#else
+					handle_private_subnet(data->iptype);
+#endif
+				}
+				else
+				{
+
+					/* check v4 not setup before, v6 can have 2 iface ip */
+					if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
+						|| ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+					{
+						IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+						if(handle_addr_evt(data) == IPACM_FAILURE)
+						{
+							return;
+						}
+
+#ifdef FEATURE_IPA_ANDROID
+						add_dummy_private_subnet_flt_rule(data->iptype);
+						handle_private_subnet_android(data->iptype);
+#else
+						handle_private_subnet(data->iptype);
+#endif
+
+						if (IPACM_Wan::isWanUP(ipa_if_num))
+						{
+							if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
+							{
+								if(IPACM_Wan::backhaul_is_sta_mode == false)
+								{
+									ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+									handle_wan_up_ex(ext_prop, IPA_IP_v4,
+												IPACM_Wan::getXlat_Mux_Id());
+								}
+								else
+								{
+									handle_wan_up(IPA_IP_v4);
+								}
+							}
+						}
+
+						if(IPACM_Wan::isWanUP_V6(ipa_if_num))
+						{
+							if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
+							{
+								memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
+								install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+								if(IPACM_Wan::backhaul_is_sta_mode == false)
+								{
+									ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+									handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+								}
+								else
+								{
+									handle_wan_up(IPA_IP_v6);
+								}
+							}
+						}
+
+						/* Post event to NAT */
+						if (data->iptype == IPA_IP_v4)
+						{
+							ipacm_cmd_q_data evt_data;
+							ipacm_event_iface_up *info;
+
+							info = (ipacm_event_iface_up *)
+								malloc(sizeof(ipacm_event_iface_up));
+							if (info == NULL)
+							{
+								IPACMERR("Unable to allocate memory\n");
+								return;
+							}
+
+							memcpy(info->ifname, dev_name, IF_NAME_LEN);
+							info->ipv4_addr = data->ipv4_addr;
+							info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+							evt_data.event = IPA_HANDLE_LAN_UP;
+							evt_data.evt_data = (void *)info;
+
+							/* Insert IPA_HANDLE_LAN_UP to command queue */
+							IPACMDBG_H("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
+							IPACMDBG_H("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+											info->ipv4_addr, info->addr_mask);
+							IPACM_EvtDispatcher::PostEvt(&evt_data);
+						}
+						IPACMDBG_H("Finish handling IPA_ADDR_ADD_EVENT for ip-family(%d)\n", data->iptype);
+					}
+
+					IPACMDBG_H("Finish handling IPA_ADDR_ADD_EVENT for ip-family(%d)\n", data->iptype);
+					/* checking if SW-RT_enable */
+					if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+					{
+						/* handle software routing enable event*/
+						IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+						handle_software_routing_enable();
+					}
+
+				}
+			}
+		}
+		break;
+#ifdef FEATURE_IPA_ANDROID
+	case IPA_HANDLE_WAN_UP_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_TETHER event\n");
+
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+			{
+				if(data_wan_tether->is_sta == false)
+				{
+					ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+					handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+				}
+				else
+				{
+					handle_wan_up(IPA_IP_v4);
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP_V6_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6_TETHER event\n");
+
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+			{
+					memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
+					install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
+					if(data_wan_tether->is_sta == false)
+					{
+						ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+						handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+					}
+					else
+					{
+						handle_wan_up(IPA_IP_v6);
+					}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_TETHER event\n");
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+			{
+				handle_wan_down(data_wan_tether->is_sta);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_V6_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER event\n");
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			/* clean up v6 RT rules*/
+			IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER in LAN-instance and need clean up client IPv6 address \n");
+			/* reset usb-client ipv6 rt-rules */
+			handle_lan_client_reset_rt(IPA_IP_v6);
+
+			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+			{
+				handle_wan_down_v6(data_wan_tether->is_sta);
+			}
+		}
+		break;
+#else
+	case IPA_HANDLE_WAN_UP:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+		{
+		if(data_wan->is_sta == false)
+		{
+				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+				handle_wan_up_ex(ext_prop, IPA_IP_v4, data_wan->xlat_mux_id);
+		}
+		else
+		{
+			handle_wan_up(IPA_IP_v4);
+		}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP_V6:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6 event\n");
+
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+		{
+			memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
+			install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+			if(data_wan->is_sta == false)
+			{
+				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+				handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+			}
+			else
+			{
+				handle_wan_up(IPA_IP_v6);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+		{
+			handle_wan_down(data_wan->is_sta);
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_V6:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6 event\n");
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		/* clean up v6 RT rules*/
+		IPACMDBG_H("Received IPA_WAN_V6_DOWN in LAN-instance and need clean up client IPv6 address \n");
+		/* reset usb-client ipv6 rt-rules */
+		handle_lan_client_reset_rt(IPA_IP_v6);
+
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+		{
+			handle_wan_down_v6(data_wan->is_sta);
+		}
+		break;
+#endif
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			IPACMDBG_H("Recieved IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT event \n");
+			IPACMDBG_H("check iface %s category: %d\n", dev_name, ipa_if_cate);
+
+			if (ipa_interface_index == ipa_if_num && ipa_if_cate == ODU_IF)
+			{
+				IPACMDBG_H("ODU iface got v4-ip \n");
+				/* first construc ODU full header */
+				if ((ipv4_header_set == false) && (ipv6_header_set == false))
+				{
+					/* construct ODU RT tbl */
+					handle_odu_hdr_init(data->mac_addr);
+					if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+					{
+						handle_odu_route_add();
+						IPACMDBG_H("construct ODU header and route rules, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+					}
+					else
+					{
+						IPACMDBG_H("construct ODU header only, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+					}
+				}
+				/* if ODU in bridge mode, directly return */
+				if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false)
+				{
+					IPACMDBG_H("ODU is in bridge mode, no action \n");
+					return;
+				}
+			}
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("ETH iface got client \n");
+				/* first construc ETH full header */
+				handle_eth_hdr_init(data->mac_addr);
+				IPACMDBG_H("construct ETH header and route rules \n");
+				/* Associate with IP and construct RT-rule */
+				if (handle_eth_client_ipaddr(data) == IPACM_FAILURE)
+				{
+					return;
+				}
+				handle_eth_client_route_rule(data->mac_addr, data->iptype);
+				if (data->iptype == IPA_IP_v4)
+				{
+					/* Add NAT rules after ipv4 RT rules are set */
+					CtList->HandleNeighIpAddrAddEvt(data);
+				}
+				eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX, data->mac_addr);
+				return;
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT event. \n");
+			IPACMDBG_H("check iface %s category: %d\n", dev_name, ipa_if_cate);
+			/* if ODU in bridge mode, directly return */
+			if (ipa_if_cate == ODU_IF && IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false)
+			{
+				IPACMDBG_H("ODU is in bridge mode, no action \n");
+				return;
+			}
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				if (data->iptype == IPA_IP_v6)
+				{
+					handle_del_ipv6_addr(data);
+					return;
+				}
+
+				eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_DEL, IPA_IP_MAX, data->mac_addr);
+
+				IPACMDBG_H("LAN iface delete client \n");
+				handle_eth_client_down_evt(data->mac_addr);
+				return;
+			}
+		}
+		break;
+
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+		/* handle software routing enable event*/
+		handle_software_routing_enable();
+		break;
+
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+		/* handle software routing disable event*/
+		handle_software_routing_disable();
+		break;
+
+	case IPA_CRADLE_WAN_MODE_SWITCH:
+	{
+		IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+		ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+		if(wan_mode == NULL)
+		{
+			IPACMERR("Event data is empty.\n");
+			return;
+		}
+
+		if(wan_mode->cradle_wan_mode == BRIDGE)
+		{
+			handle_cradle_wan_mode_switch(true);
+		}
+		else
+		{
+			handle_cradle_wan_mode_switch(false);
+		}
+	}
+	break;
+
+	case IPA_TETHERING_STATS_UPDATE_EVENT:
+	{
+		IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+		if (IPACM_Wan::isWanUP(ipa_if_num) || IPACM_Wan::isWanUP_V6(ipa_if_num))
+		{
+			if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+			{
+				ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+				IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data->ipa_stats_type);
+				IPACMDBG("Received %d UL, %d DL pipe stats\n",data->ul_src_pipe_stats_list_len,
+					data->dl_dst_pipe_stats_list_len);
+				if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+				{
+					IPACMERR("not valid pipe stats enum(%d)\n", data->ipa_stats_type);
+					return;
+				}
+				handle_tethering_stats_event(data);
+			}
+		}
+	}
+	break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+
+int IPACM_Lan::handle_del_ipv6_addr(ipacm_event_data_all *data)
+{
+	uint32_t tx_index;
+	uint32_t rt_hdl;
+	int num_v6 =0, clnt_indx;
+
+	clnt_indx = get_eth_client_index(data->mac_addr);
+	if (clnt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMERR("eth client not found/attached \n");
+		return IPACM_FAILURE;
+	}
+
+	if(data->iptype == IPA_IP_v6)
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0))
+		{
+			IPACMDBG_H("ipv6 address got: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			for(num_v6=0;num_v6 < get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+			{
+				if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] &&
+					data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] &&
+					data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] &&
+					data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3])
+				{
+					IPACMDBG_H("ipv6 addr is found at position:%d for client:%d\n", num_v6, clnt_indx);
+					break;
+				}
+			}
+		}
+		if (num_v6 == IPV6_NUM_ADDR)
+		{
+			IPACMDBG_H("ipv6 addr is not found. \n");
+			return IPACM_FAILURE;
+		}
+
+		for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6 != 0))
+			{
+				IPACMDBG_H("Delete client index %d ipv6 RT-rules for %d-st ipv6 for tx:%d\n", clnt_indx, num_v6, tx_index);
+				rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+				{
+					return IPACM_FAILURE;
+				}
+				rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+				{
+					return IPACM_FAILURE;
+				}
+				get_client_memptr(eth_client, clnt_indx)->ipv6_set--;
+				get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6--;
+
+				for(num_v6;num_v6< get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+				{
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][0];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][1];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][2];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][3];
+					get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
+						get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6+1];
+					get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
+						get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6+1];
+				}
+			}
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+/* delete filter rule for wan_down event for IPv4*/
+int IPACM_Lan::handle_wan_down(bool is_sta_mode)
+{
+	ipa_fltr_installed_notif_req_msg_v01 flt_index;
+	int fd;
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+	if(is_sta_mode == false)
+	{
+		if (num_wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES)
+		{
+			IPACMERR("number of wan_ul_fl_rule_v4 (%d) > MAX_WAN_UL_FILTER_RULES (%d), aborting...\n", num_wan_ul_fl_rule_v4, MAX_WAN_UL_FILTER_RULES);
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v4,
+			IPA_IP_v4, num_wan_ul_fl_rule_v4) == false)
+		{
+			IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_wan_ul_fl_rule_v4);
+
+		memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+		num_wan_ul_fl_rule_v4 = 0;
+		modem_ul_v4_set = false;
+
+		memset(&flt_index, 0, sizeof(flt_index));
+		flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+		flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+		flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id_valid = 1;
+		flt_index.rule_id_len = 0;
+#endif
+		flt_index.embedded_pipe_index_valid = 1;
+		flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+		flt_index.retain_header_valid = 1;
+		flt_index.retain_header = 0;
+		flt_index.embedded_call_mux_id_valid = 1;
+		flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
+
+		if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+		{
+			IPACMERR("Error sending filtering rule index, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0], IPA_IP_v4, 1) == false)
+		{
+			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+	}
+
+	close(fd);
+	return IPACM_SUCCESS;
+}
+
+/* handle new_address event*/
+int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	const int NUM_RULES = 1;
+	int num_ipv6_addr;
+	int res = IPACM_SUCCESS;
+
+	IPACMDBG_H("set route/filter rule ip-type: %d \n", data->iptype);
+
+/* Add private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+	if (data->iptype == IPA_IP_v4)
+	{
+		IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+		if_ipv4_subnet = (data->ipv4_addr >> 8) << 8;
+		IPACMDBG_H(" Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		if(IPACM_Iface::ipacmcfg->AddPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+		{
+			IPACMERR(" can't Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		}
+	}
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+	/* Update the IP Type. */
+	config_ip_type(data->iptype);
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+							NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+		if (!rt_rule)
+		{
+			IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = data->iptype;
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;  //go to A5
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = true;
+#endif
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+		/* initial multicast/broadcast/fragment filter rule */
+
+		init_fl_rule(data->iptype);
+		install_ipv4_icmp_flt_rule();
+
+		/* populate the flt rule offset for eth bridge */
+		eth_bridge_flt_rule_offset[data->iptype] = ipv4_icmp_flt_rule_hdl[0];
+		eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v4, NULL);
+	}
+	else
+	{
+	    /* check if see that v6-addr already or not*/
+	    for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
+	    {
+            if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+	           (ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+	           (ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+	           (ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+            {
+				return IPACM_FAILURE;
+				break;
+	        }
+	    }
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+							NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+		if (!rt_rule)
+		{
+			IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = data->iptype;
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;  //go to A5
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
+		ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
+		ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
+		ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = true;
+#endif
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
+
+		/* setup same rule for v6_wan table*/
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
+
+		IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, num_dft_rt_v6: %d \n",
+		          dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
+		          dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],num_dft_rt_v6);
+
+		if (num_dft_rt_v6 == 0)
+		{
+			install_ipv6_icmp_flt_rule();
+
+			/* populate the flt rule offset for eth bridge */
+			eth_bridge_flt_rule_offset[data->iptype] = ipv6_icmp_flt_rule_hdl[0];
+			eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v6, NULL);
+
+			init_fl_rule(data->iptype);
+		}
+		num_dft_rt_v6++;
+		IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
+	}
+
+	IPACMDBG_H("finish route/filter rule ip-type: %d, res(%d)\n", data->iptype, res);
+
+fail:
+	free(rt_rule);
+	return res;
+}
+
+/* configure private subnet filter rules*/
+int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i;
+
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG_H("lan->handle_private_subnet(); set route/filter rule \n");
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if (iptype == IPA_IP_v4)
+	{
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1,
+							sizeof(struct ipa_ioc_add_flt_rule) +
+							(IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+							);
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v4;
+		m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+		/* Make LAN-traffic always go A5, use default IPA-RT table */
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
+		{
+			IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_default_v4);
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+
+		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+		{
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.rule.retain_hdr = 1;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+                        /* Support private subnet feature including guest-AP can't talk to primary AP etc */
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
+			IPACMDBG_H(" private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
+
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(flt_rule_entry.rule.attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+			memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+			IPACMDBG_H("Loop %d  5\n", i);
+		}
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+
+		/* copy filter rule hdls */
+		for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+		{
+			private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+		}
+		free(m_pFilteringTable);
+	}
+	else
+	{
+		IPACMDBG_H("No private subnet rules for ipv6 iface %s\n", dev_name);
+	}
+	return IPACM_SUCCESS;
+}
+
+
+/* for STA mode wan up:  configure filter rule for wan_up event*/
+int IPACM_Lan::handle_wan_up(ipa_ip_type ip_type)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int len = 0;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG_H("set WAN interface as default filter rule\n");
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(ip_type == IPA_IP_v4)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) + (1 * sizeof(struct ipa_flt_rule_add));
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (m_pFilteringTable == NULL)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v4;
+		m_pFilteringTable->num_rules = (uint8_t)1;
+
+		IPACMDBG_H("Retrieving routing hanle for table: %s\n",
+						 IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+		{
+			IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+							 &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+		IPACMDBG_H("Routing hanle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		if(IPACM_Wan::isWan_Bridge_Mode())
+		{
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		}
+		else
+		{
+			flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+		}
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+		memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+			IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+							 m_pFilteringTable->rules[0].flt_rule_hdl,
+							 m_pFilteringTable->rules[0].status);
+		}
+
+
+		/* copy filter hdls  */
+		lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		free(m_pFilteringTable);
+	}
+	else if(ip_type == IPA_IP_v6)
+	{
+		/* add default v6 filter rule */
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_flt_rule) +
+					1 * sizeof(struct ipa_flt_rule_add));
+
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v6;
+		m_pFilteringTable->num_rules = (uint8_t)1;
+
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+		{
+			IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+			IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+		}
+
+		/* copy filter hdls */
+		dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		free(m_pFilteringTable);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::handle_wan_up_ex(ipacm_ext_prop *ext_prop, ipa_ip_type iptype, uint8_t xlat_mux_id)
+{
+	int fd, ret = IPACM_SUCCESS, cnt;
+	IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
+	struct ipa_ioc_write_qmapid mux;
+
+	if(rx_prop != NULL)
+	{
+		/* give mud ID to IPA-driver for WLAN/LAN pkts */
+		fd = open(IPA_DEVICE_NAME, O_RDWR);
+		if (0 == fd)
+		{
+			IPACMDBG_H("Failed opening %s.\n", IPA_DEVICE_NAME);
+			return IPACM_FAILURE;
+		}
+
+		mux.qmap_id = ipacm_config->GetQmapId();
+		for(cnt=0; cnt<rx_prop->num_rx_props; cnt++)
+		{
+			mux.client = rx_prop->rx[cnt].src_pipe;
+			ret = ioctl(fd, IPA_IOC_WRITE_QMAPID, &mux);
+			if (ret)
+			{
+				IPACMERR("Failed to write mux id %d\n", mux.qmap_id);
+				close(fd);
+				return IPACM_FAILURE;
+			}
+		}
+		close(fd);
+	}
+
+	/* check only add static UL filter rule once */
+	if (num_dft_rt_v6 ==1 && iptype ==IPA_IP_v6 && modem_ul_v6_set == false)
+	{
+		IPACMDBG_H("IPA_IP_v6 num_dft_rt_v6 %d xlat_mux_id: %d modem_ul_v6_set: %d\n", num_dft_rt_v6, xlat_mux_id, modem_ul_v6_set);
+		ret = handle_uplink_filter_rule(ext_prop, iptype, xlat_mux_id);
+		modem_ul_v6_set = true;
+	} else if (iptype ==IPA_IP_v4 && modem_ul_v4_set == false) {
+		IPACMDBG_H("IPA_IP_v4 xlat_mux_id: %d, modem_ul_v4_set %d\n", xlat_mux_id, modem_ul_v4_set);
+		ret = handle_uplink_filter_rule(ext_prop, iptype, xlat_mux_id);
+		modem_ul_v4_set = true;
+	} else {
+		IPACMDBG_H("ip-type: %d modem_ul_v4_set: %d, modem_ul_v6_set %d\n", iptype, modem_ul_v4_set, modem_ul_v6_set);
+	}
+	return ret;
+}
+
+/* handle ETH client initial, construct full headers (tx property) */
+int IPACM_Lan::handle_eth_hdr_init(uint8_t *mac_addr)
+{
+
+#define ETH_IFACE_INDEX_LEN 2
+
+	int res = IPACM_SUCCESS, len = 0;
+	char index[ETH_IFACE_INDEX_LEN];
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+	uint32_t cnt;
+	int clnt_indx;
+
+	clnt_indx = get_eth_client_index(mac_addr);
+
+	if (clnt_indx != IPACM_INVALID_INDEX)
+	{
+		IPACMERR("eth client is found/attached already with index %d \n", clnt_indx);
+		return IPACM_FAILURE;
+	}
+
+	/* add header to IPA */
+	if (num_eth_client >= IPA_MAX_NUM_ETH_CLIENTS)
+	{
+		IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_ETH_CLIENTS);
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG_H("ETH client number: %d\n", num_eth_client);
+
+	memcpy(get_client_memptr(eth_client, num_eth_client)->mac,
+				 mac_addr,
+				 sizeof(get_client_memptr(eth_client, num_eth_client)->mac));
+
+
+	IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(eth_client, num_eth_client)->mac[0],
+					 get_client_memptr(eth_client, num_eth_client)->mac[1],
+					 get_client_memptr(eth_client, num_eth_client)->mac[2],
+					 get_client_memptr(eth_client, num_eth_client)->mac[3],
+					 get_client_memptr(eth_client, num_eth_client)->mac[4],
+					 get_client_memptr(eth_client, num_eth_client)->mac[5]);
+
+	/* add header to IPA */
+	if(tx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+		if (pHeaderDescriptor == NULL)
+		{
+			IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+			return IPACM_FAILURE;
+		}
+
+		/* copy partial header for v4*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+				 if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+				 {
+								IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+								memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+								memcpy(sCopyHeader.name,
+											 tx_prop->tx[cnt].hdr_name,
+											 sizeof(sCopyHeader.name));
+
+								IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+								if (m_header.CopyHeader(&sCopyHeader) == false)
+								{
+									PERROR("ioctl copy header failed");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+								IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+								if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+								{
+									IPACMERR("header oversize\n");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+								else
+								{
+									memcpy(pHeaderDescriptor->hdr[0].hdr,
+												 sCopyHeader.hdr,
+												 sCopyHeader.hdr_len);
+								}
+
+								/* copy client mac_addr to partial header */
+								if (sCopyHeader.is_eth2_ofst_valid)
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+											 mac_addr,
+											 IPA_MAC_ADDR_SIZE);
+								}
+								/* replace src mac to bridge mac_addr if any  */
+								if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+											IPACM_Iface::ipacmcfg->bridge_mac,
+											IPA_MAC_ADDR_SIZE);
+									IPACMDBG_H("device is in bridge mode \n");
+								}
+
+								pHeaderDescriptor->commit = true;
+								pHeaderDescriptor->num_hdrs = 1;
+
+								memset(pHeaderDescriptor->hdr[0].name, 0,
+											 sizeof(pHeaderDescriptor->hdr[0].name));
+
+								snprintf(index,sizeof(index), "%d", ipa_if_num);
+								strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+								pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+								if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+								{
+									IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								snprintf(index,sizeof(index), "%d", header_name_count);
+								if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+								{
+									IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+								pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+								pHeaderDescriptor->hdr[0].is_partial = 0;
+								pHeaderDescriptor->hdr[0].status = -1;
+
+					 if (m_header.AddHeader(pHeaderDescriptor) == false ||
+							pHeaderDescriptor->hdr[0].status != 0)
+					 {
+						IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+						res = IPACM_FAILURE;
+						goto fail;
+					 }
+
+					get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+					IPACMDBG_H("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
+												 num_eth_client,
+												 pHeaderDescriptor->hdr[0].name,
+												 get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4);
+									get_client_memptr(eth_client, num_eth_client)->ipv4_header_set=true;
+
+					break;
+				 }
+		}
+
+
+		/* copy partial header for v6*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+			{
+
+				IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+				memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+				memcpy(sCopyHeader.name,
+						tx_prop->tx[cnt].hdr_name,
+							sizeof(sCopyHeader.name));
+
+				IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+				if (m_header.CopyHeader(&sCopyHeader) == false)
+				{
+					PERROR("ioctl copy header failed");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+				IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+				if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+				{
+					IPACMERR("header oversize\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					memcpy(pHeaderDescriptor->hdr[0].hdr,
+							sCopyHeader.hdr,
+								sCopyHeader.hdr_len);
+				}
+
+				/* copy client mac_addr to partial header */
+				if (sCopyHeader.is_eth2_ofst_valid)
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+						mac_addr,
+						IPA_MAC_ADDR_SIZE);
+				}
+				/* replace src mac to bridge mac_addr if any  */
+				if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+							IPACM_Iface::ipacmcfg->bridge_mac,
+							IPA_MAC_ADDR_SIZE);
+					IPACMDBG_H("device is in bridge mode \n");
+				}
+
+				pHeaderDescriptor->commit = true;
+				pHeaderDescriptor->num_hdrs = 1;
+
+				memset(pHeaderDescriptor->hdr[0].name, 0,
+					 sizeof(pHeaderDescriptor->hdr[0].name));
+
+				snprintf(index,sizeof(index), "%d", ipa_if_num);
+				strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+				pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+				if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				snprintf(index,sizeof(index), "%d", header_name_count);
+				if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+				pHeaderDescriptor->hdr[0].is_partial = 0;
+				pHeaderDescriptor->hdr[0].status = -1;
+
+				if (m_header.AddHeader(pHeaderDescriptor) == false ||
+						pHeaderDescriptor->hdr[0].status != 0)
+				{
+					IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+				IPACMDBG_H("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
+						 num_eth_client,
+						 pHeaderDescriptor->hdr[0].name,
+									 get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6);
+
+									get_client_memptr(eth_client, num_eth_client)->ipv6_header_set=true;
+
+				break;
+
+			}
+		}
+		/* initialize wifi client*/
+		get_client_memptr(eth_client, num_eth_client)->route_rule_set_v4 = false;
+		get_client_memptr(eth_client, num_eth_client)->route_rule_set_v6 = 0;
+		get_client_memptr(eth_client, num_eth_client)->ipv4_set = false;
+		get_client_memptr(eth_client, num_eth_client)->ipv6_set = 0;
+		num_eth_client++;
+		header_name_count++; //keep increasing header_name_count
+		res = IPACM_SUCCESS;
+		IPACMDBG_H("eth client number: %d\n", num_eth_client);
+	}
+	else
+	{
+		return res;
+	}
+fail:
+	free(pHeaderDescriptor);
+	return res;
+}
+
+/*handle eth client */
+int IPACM_Lan::handle_eth_client_ipaddr(ipacm_event_data_all *data)
+{
+	int clnt_indx;
+	int v6_num;
+	uint32_t ipv6_link_local_prefix = 0xFE800000;
+	uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
+
+	IPACMDBG_H("number of eth clients: %d\n", num_eth_client);
+	IPACMDBG_H("event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 data->mac_addr[0],
+					 data->mac_addr[1],
+					 data->mac_addr[2],
+					 data->mac_addr[3],
+					 data->mac_addr[4],
+					 data->mac_addr[5]);
+
+	clnt_indx = get_eth_client_index(data->mac_addr);
+
+		if (clnt_indx == IPACM_INVALID_INDEX)
+		{
+			IPACMERR("eth client not found/attached \n");
+			return IPACM_FAILURE;
+		}
+
+	IPACMDBG_H("Ip-type received %d\n", data->iptype);
+	if (data->iptype == IPA_IP_v4)
+	{
+		IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+		if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+		{
+			if (get_client_memptr(eth_client, clnt_indx)->ipv4_set == false)
+			{
+				get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				get_client_memptr(eth_client, clnt_indx)->ipv4_set = true;
+			}
+			else
+			{
+			   /* check if client got new IPv4 address*/
+			   if(data->ipv4_addr == get_client_memptr(eth_client, clnt_indx)->v4_addr)
+			   {
+				IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+				 return IPACM_FAILURE;
+			   }
+			   else
+			   {
+					IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+					/* delete NAT rules first */
+					CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clnt_indx)->v4_addr);
+					delete_eth_rtrules(clnt_indx,IPA_IP_v4);
+					get_client_memptr(eth_client, clnt_indx)->route_rule_set_v4 = false;
+					get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				}
+			}
+		}
+		else
+		{
+		    IPACMDBG_H("Invalid client IPv4 address \n");
+		    return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+		{
+			IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+				memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+			{
+				IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+				return IPACM_FAILURE;
+			}
+
+            if(get_client_memptr(eth_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+			{
+
+		       for(v6_num=0;v6_num < get_client_memptr(eth_client, clnt_indx)->ipv6_set;v6_num++)
+				{
+					if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][0] &&
+			           data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][1] &&
+			  	        data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][2] &&
+			  	         data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][3])
+					{
+						IPACMDBG_H("Already see this ipv6 addr at position: %d for client:%d\n", v6_num, clnt_indx);
+						return IPACM_FAILURE; /* not setup the RT rules*/
+					}
+				}
+
+		       /* not see this ipv6 before for wifi client*/
+			   get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+			   get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+			   get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+			   get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+			   get_client_memptr(eth_client, clnt_indx)->ipv6_set++;
+		    }
+		    else
+		    {
+		        IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+				return IPACM_FAILURE; /* not setup the RT rules*/
+		    }
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle eth client routing rule*/
+int IPACM_Lan::handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	uint32_t tx_index;
+	int eth_index,v6_num;
+	const int NUM = 1;
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	eth_index = get_eth_client_index(mac_addr);
+	if (eth_index == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("eth client not found/attached \n");
+		return IPACM_SUCCESS;
+	}
+
+	if (iptype==IPA_IP_v4) {
+		IPACMDBG_H("eth client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", eth_index, iptype,
+					 get_client_memptr(eth_client, eth_index)->ipv4_set,
+					 get_client_memptr(eth_client, eth_index)->route_rule_set_v4);
+	} else {
+		IPACMDBG_H("eth client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", eth_index, iptype,
+					 get_client_memptr(eth_client, eth_index)->ipv6_set,
+					 get_client_memptr(eth_client, eth_index)->route_rule_set_v6);
+	}
+	/* Add default routing rules if not set yet */
+	if ((iptype == IPA_IP_v4
+			 && get_client_memptr(eth_client, eth_index)->route_rule_set_v4 == false
+			 && get_client_memptr(eth_client, eth_index)->ipv4_set == true)
+			|| (iptype == IPA_IP_v6
+		            && get_client_memptr(eth_client, eth_index)->route_rule_set_v6 < get_client_memptr(eth_client, eth_index)->ipv6_set
+					))
+	{
+
+        /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		if (tx_prop != NULL)
+		{
+			IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+			IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+		}
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_add));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = (uint8_t)NUM;
+		rt_rule->ip = iptype;
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if(iptype != tx_prop->tx[tx_index].ip)
+		    {
+				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+						tx_index, tx_prop->tx[tx_index].ip,iptype);
+		   	        continue;
+		    }
+
+  	   	    rt_rule_entry = &rt_rule->rules[0];
+			rt_rule_entry->at_rear = 0;
+
+			if (iptype == IPA_IP_v4)
+			{
+		        IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", eth_index,
+		  		        get_client_memptr(eth_client, eth_index)->v4_addr);
+
+                IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+		  				 eth_index,
+		  				 get_client_memptr(eth_client, eth_index)->hdr_hdl_v4);
+				strlcpy(rt_rule->rt_tbl_name,
+								IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+								sizeof(rt_rule->rt_tbl_name));
+				rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+			    rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			    memcpy(&rt_rule_entry->rule.attrib,
+						 &tx_prop->tx[tx_index].attrib,
+						 sizeof(rt_rule_entry->rule.attrib));
+			    rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		   	    rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v4;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(eth_client, eth_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+				rt_rule_entry->rule.hashable = false;
+#endif
+			    if (false == m_routing.AddRoutingRule(rt_rule))
+  	            {
+  	          	            IPACMERR("Routing rule addition failed!\n");
+  	          	            free(rt_rule);
+  	          	            return IPACM_FAILURE;
+			    }
+
+			    /* copy ipv4 RT hdl */
+		        get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
+  	   	        rt_rule->rules[0].rt_rule_hdl;
+		        IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+		      	get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4, iptype);
+
+  	   	    } else {
+
+		        for(v6_num = get_client_memptr(eth_client, eth_index)->route_rule_set_v6;v6_num < get_client_memptr(eth_client, eth_index)->ipv6_set;v6_num++)
+			    {
+                    IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+		  	    			 eth_index,
+		  	    			 get_client_memptr(eth_client, eth_index)->hdr_hdl_v6);
+
+		            /* v6 LAN_RT_TBL */
+				strlcpy(rt_rule->rt_tbl_name,
+			    					IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+			    					sizeof(rt_rule->rt_tbl_name));
+				rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		            /* Support QCMAP LAN traffic feature, send to A5 */
+					rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+			        memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+		   	        rt_rule_entry->rule.hdr_hdl = 0;
+			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][0];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+					rt_rule_entry->rule.hashable = true;
+#endif
+   	                if (false == m_routing.AddRoutingRule(rt_rule))
+  	                {
+  	                	    IPACMERR("Routing rule addition failed!\n");
+  	                	    free(rt_rule);
+  	                	    return IPACM_FAILURE;
+			        }
+
+		            get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+		            IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+		            				 get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num], iptype);
+
+			        /*Copy same rule to v6 WAN RT TBL*/
+				strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+				rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+				/* Downlink traffic from Wan iface, directly through IPA */
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			        memcpy(&rt_rule_entry->rule.attrib,
+						 &tx_prop->tx[tx_index].attrib,
+						 sizeof(rt_rule_entry->rule.attrib));
+		   	        rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v6;
+			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][0];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
+		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+					rt_rule_entry->rule.hashable = true;
+#endif
+		            if (false == m_routing.AddRoutingRule(rt_rule))
+		            {
+							IPACMERR("Routing rule addition failed!\n");
+							free(rt_rule);
+							return IPACM_FAILURE;
+		            }
+
+		            get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+		            				 get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num], iptype);
+			    }
+			}
+
+  	    } /* end of for loop */
+
+		free(rt_rule);
+
+		if (iptype == IPA_IP_v4)
+		{
+			get_client_memptr(eth_client, eth_index)->route_rule_set_v4 = true;
+		}
+		else
+		{
+			get_client_memptr(eth_client, eth_index)->route_rule_set_v6 = get_client_memptr(eth_client, eth_index)->ipv6_set;
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+/* handle odu client initial, construct full headers (tx property) */
+int IPACM_Lan::handle_odu_hdr_init(uint8_t *mac_addr)
+{
+	int res = IPACM_SUCCESS, len = 0;
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+	uint32_t cnt;
+
+	IPACMDBG("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	/* add header to IPA */
+	if(tx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+		if (pHeaderDescriptor == NULL)
+		{
+			IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+			return IPACM_FAILURE;
+		}
+
+		/* copy partial header for v4*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+				 if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+				 {
+								IPACMDBG("Got partial v4-header name from %d tx props\n", cnt);
+								memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+								memcpy(sCopyHeader.name,
+											tx_prop->tx[cnt].hdr_name,
+											 sizeof(sCopyHeader.name));
+								IPACMDBG("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+								if (m_header.CopyHeader(&sCopyHeader) == false)
+								{
+									PERROR("ioctl copy header failed");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+								IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+								if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+								{
+									IPACMERR("header oversize\n");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+								else
+								{
+									memcpy(pHeaderDescriptor->hdr[0].hdr,
+												 sCopyHeader.hdr,
+												 sCopyHeader.hdr_len);
+								}
+								/* copy client mac_addr to partial header */
+								if (sCopyHeader.is_eth2_ofst_valid)
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+											 mac_addr,
+											 IPA_MAC_ADDR_SIZE);
+								}
+								/* replace src mac to bridge mac_addr if any  */
+								if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+											IPACM_Iface::ipacmcfg->bridge_mac,
+											IPA_MAC_ADDR_SIZE);
+									IPACMDBG_H("device is in bridge mode \n");
+								}
+
+								pHeaderDescriptor->commit = true;
+								pHeaderDescriptor->num_hdrs = 1;
+
+								memset(pHeaderDescriptor->hdr[0].name, 0,
+											 sizeof(pHeaderDescriptor->hdr[0].name));
+								strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name));
+								pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+								pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+								pHeaderDescriptor->hdr[0].is_partial = 0;
+								pHeaderDescriptor->hdr[0].status = -1;
+
+					 if (m_header.AddHeader(pHeaderDescriptor) == false ||
+							pHeaderDescriptor->hdr[0].status != 0)
+					 {
+						IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+						res = IPACM_FAILURE;
+						goto fail;
+					 }
+
+					ODU_hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+					ipv4_header_set = true ;
+					IPACMDBG(" ODU v4 full header name:%s header handle:(0x%x)\n",
+										 pHeaderDescriptor->hdr[0].name,
+												 ODU_hdr_hdl_v4);
+					break;
+				 }
+		}
+
+
+		/* copy partial header for v6*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+			{
+
+				IPACMDBG("Got partial v6-header name from %d tx props\n", cnt);
+				memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+				memcpy(sCopyHeader.name,
+						tx_prop->tx[cnt].hdr_name,
+							sizeof(sCopyHeader.name));
+
+				IPACMDBG("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+				if (m_header.CopyHeader(&sCopyHeader) == false)
+				{
+					PERROR("ioctl copy header failed");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+				if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+				{
+					IPACMERR("header oversize\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					memcpy(pHeaderDescriptor->hdr[0].hdr,
+							sCopyHeader.hdr,
+								sCopyHeader.hdr_len);
+				}
+
+				/* copy client mac_addr to partial header */
+				if (sCopyHeader.is_eth2_ofst_valid)
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+					 mac_addr,
+					 IPA_MAC_ADDR_SIZE);
+				}
+				/* replace src mac to bridge mac_addr if any  */
+				if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+							IPACM_Iface::ipacmcfg->bridge_mac,
+							IPA_MAC_ADDR_SIZE);
+					IPACMDBG_H("device is in bridge mode \n");
+				}
+
+				pHeaderDescriptor->commit = true;
+				pHeaderDescriptor->num_hdrs = 1;
+
+				memset(pHeaderDescriptor->hdr[0].name, 0,
+					 sizeof(pHeaderDescriptor->hdr[0].name));
+
+				strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name));
+				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+				pHeaderDescriptor->hdr[0].is_partial = 0;
+				pHeaderDescriptor->hdr[0].status = -1;
+
+				if (m_header.AddHeader(pHeaderDescriptor) == false ||
+						pHeaderDescriptor->hdr[0].status != 0)
+				{
+					IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				ODU_hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+				ipv6_header_set = true ;
+				IPACMDBG(" ODU v4 full header name:%s header handle:(0x%x)\n",
+									 pHeaderDescriptor->hdr[0].name,
+											 ODU_hdr_hdl_v6);
+				break;
+			}
+		}
+	}
+fail:
+	free(pHeaderDescriptor);
+	return res;
+}
+
+
+/* handle odu default route rule configuration */
+int IPACM_Lan::handle_odu_route_add()
+{
+	/* add default WAN route */
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	uint32_t tx_index;
+	const int NUM = 1;
+
+	if(tx_prop == NULL)
+	{
+	  IPACMDBG_H("No tx properties, ignore default route setting\n");
+	  return IPACM_SUCCESS;
+	}
+
+	rt_rule = (struct ipa_ioc_add_rt_rule *)
+		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_add));
+
+	if (!rt_rule)
+	{
+		IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = (uint8_t)NUM;
+
+
+	IPACMDBG_H("WAN table created %s \n", rt_rule->rt_tbl_name);
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = true;
+
+	for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+	{
+
+		if (IPA_IP_v4 == tx_prop->tx[tx_index].ip)
+		{
+			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, sizeof(rt_rule->rt_tbl_name));
+			rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v4;
+			rt_rule->ip = IPA_IP_v4;
+		}
+		else
+		{
+			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, sizeof(rt_rule->rt_tbl_name));
+			rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v6;
+			rt_rule->ip = IPA_IP_v6;
+		}
+
+		rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+		memcpy(&rt_rule_entry->rule.attrib,
+					 &tx_prop->tx[tx_index].attrib,
+					 sizeof(rt_rule_entry->rule.attrib));
+
+		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		if (IPA_IP_v4 == tx_prop->tx[tx_index].ip)
+		{
+			rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
+			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+#ifdef FEATURE_IPA_V3
+			rt_rule_entry->rule.hashable = true;
+#endif
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule addition failed!\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+			odu_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG_H("Got ipv4 ODU-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+						 odu_route_rule_v4_hdl[tx_index],
+						 tx_index,
+						 IPA_IP_v4);
+		}
+		else
+		{
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+			rt_rule_entry->rule.hashable = true;
+#endif
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule addition failed!\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+			odu_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG_H("Set ipv6 ODU-route rule hdl for v6_lan_table:0x%x,tx:%d,ip-type: %d \n",
+					odu_route_rule_v6_hdl[tx_index],
+					tx_index,
+					IPA_IP_v6);
+		}
+	}
+	free(rt_rule);
+	return IPACM_SUCCESS;
+}
+
+/* handle odu default route rule deletion */
+int IPACM_Lan::handle_odu_route_del()
+{
+	uint32_t tx_index;
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+		return IPACM_SUCCESS;
+	}
+
+	for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+	{
+		if (tx_prop->tx[tx_index].ip == IPA_IP_v4)
+		{
+			IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n",
+					tx_index, tx_prop->tx[tx_index].ip,IPA_IP_v4);
+
+			if (m_routing.DeleteRoutingHdl(odu_route_rule_v4_hdl[tx_index], IPA_IP_v4)
+					== false)
+			{
+				IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, odu_route_rule_v4_hdl[tx_index], tx_index);
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n",
+					tx_index, tx_prop->tx[tx_index].ip,IPA_IP_v6);
+
+			if (m_routing.DeleteRoutingHdl(odu_route_rule_v6_hdl[tx_index], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, odu_route_rule_v6_hdl[tx_index], tx_index);
+				return IPACM_FAILURE;
+			}
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle eth client del mode*/
+int IPACM_Lan::handle_eth_client_down_evt(uint8_t *mac_addr)
+{
+	int clt_indx;
+	uint32_t tx_index;
+	int num_eth_client_tmp = num_eth_client;
+	int num_v6;
+
+	IPACMDBG_H("total client: %d\n", num_eth_client_tmp);
+
+	clt_indx = get_eth_client_index(mac_addr);
+	if (clt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("eth client not attached\n");
+		return IPACM_SUCCESS;
+	}
+
+	/* First reset nat rules and then route rules */
+	if(get_client_memptr(eth_client, clt_indx)->ipv4_set == true)
+	{
+			IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, clt_indx)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clt_indx)->v4_addr);
+ 	}
+
+	if (delete_eth_rtrules(clt_indx, IPA_IP_v4))
+	{
+		IPACMERR("unbale to delete ecm-client v4 route rules for index: %d\n", clt_indx);
+		return IPACM_FAILURE;
+	}
+
+	if (delete_eth_rtrules(clt_indx, IPA_IP_v6))
+	{
+		IPACMERR("unbale to delete ecm-client v6 route rules for index: %d\n", clt_indx);
+		return IPACM_FAILURE;
+	}
+
+	/* Delete eth client header */
+	if(get_client_memptr(eth_client, clt_indx)->ipv4_header_set == true)
+	{
+		if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4)
+				== false)
+		{
+			return IPACM_FAILURE;
+		}
+		get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
+	}
+
+	if(get_client_memptr(eth_client, clt_indx)->ipv6_header_set == true)
+	{
+		if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6)
+				== false)
+		{
+			return IPACM_FAILURE;
+		}
+		get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
+	}
+
+	/* Reset ip_set to 0*/
+	get_client_memptr(eth_client, clt_indx)->ipv4_set = false;
+	get_client_memptr(eth_client, clt_indx)->ipv6_set = 0;
+	get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
+	get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
+	get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false;
+	get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0;
+
+	for (; clt_indx < num_eth_client_tmp - 1; clt_indx++)
+	{
+		memcpy(get_client_memptr(eth_client, clt_indx)->mac,
+					 get_client_memptr(eth_client, (clt_indx + 1))->mac,
+					 sizeof(get_client_memptr(eth_client, clt_indx)->mac));
+
+		get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v4;
+		get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v6;
+		get_client_memptr(eth_client, clt_indx)->v4_addr = get_client_memptr(eth_client, (clt_indx + 1))->v4_addr;
+
+		get_client_memptr(eth_client, clt_indx)->ipv4_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_set;
+		get_client_memptr(eth_client, clt_indx)->ipv6_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_set;
+		get_client_memptr(eth_client, clt_indx)->ipv4_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_header_set;
+		get_client_memptr(eth_client, clt_indx)->ipv6_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_header_set;
+
+		get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v4;
+		get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v6;
+
+        for (num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->ipv6_set;num_v6++)
+	    {
+		    get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][0] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][0];
+		    get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][1] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][1];
+		    get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][2] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][2];
+		    get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][3] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][3];
+        }
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
+				 get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4;
+
+			for(num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->route_rule_set_v6;num_v6++)
+			{
+			  get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
+			   	 get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+			  get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
+			   	 get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+		    }
+		}
+	}
+
+	IPACMDBG_H(" %d eth client deleted successfully \n", num_eth_client);
+	num_eth_client = num_eth_client - 1;
+	IPACMDBG_H(" Number of eth client: %d\n", num_eth_client);
+
+	/* Del RM dependency */
+	if(num_eth_client == 0)
+	{
+		/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule*/
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		if (tx_prop != NULL)
+		{
+			IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+			IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle LAN iface down event*/
+int IPACM_Lan::handle_down_evt()
+{
+	int i;
+	int res = IPACM_SUCCESS;
+
+	IPACMDBG_H("lan handle_down_evt\n ");
+	if (ipa_if_cate == ODU_IF)
+	{
+		/* delete ODU default RT rules */
+		if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+		{
+			IPACMDBG_H("eMBMS enable, delete eMBMS DL RT rule\n");
+			handle_odu_route_del();
+		}
+
+		/* delete full header */
+		if (ipv4_header_set)
+		{
+			if (m_header.DeleteHeaderHdl(ODU_hdr_hdl_v4)
+					== false)
+			{
+					IPACMERR("ODU ipv4 header delete fail\n");
+					res = IPACM_FAILURE;
+					goto fail;
+			}
+			IPACMDBG_H("ODU ipv4 header delete success\n");
+		}
+
+		if (ipv6_header_set)
+		{
+			if (m_header.DeleteHeaderHdl(ODU_hdr_hdl_v6)
+					== false)
+			{
+				IPACMERR("ODU ipv6 header delete fail\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			IPACMERR("ODU ipv6 header delete success\n");
+		}
+	}
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
+	/* delete wan filter rule */
+	if (IPACM_Wan::isWanUP(ipa_if_num) && rx_prop != NULL)
+	{
+		IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+		handle_wan_down(IPACM_Wan::backhaul_is_sta_mode);
+	}
+
+	if (IPACM_Wan::isWanUP_V6(ipa_if_num) && rx_prop != NULL)
+	{
+		IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+		handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
+	}
+
+	/* delete default filter rules */
+	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+	{
+		if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
+
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Deleting Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+
+		/* free private-subnet ipv4 filter rules */
+		if (IPACM_Iface::ipacmcfg->ipa_num_private_subnet > IPA_PRIV_SUBNET_FILTER_RULE_HANDLES)
+		{
+			IPACMERR(" the number of rules are bigger than array, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+#ifdef FEATURE_IPA_ANDROID
+		if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES) == false)
+		{
+			IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+#else
+		if (m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+		{
+			IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#endif
+		IPACMDBG_H("Deleted private subnet v4 filter rules successfully.\n");
+	}
+	IPACMDBG_H("Finished delete default iface ipv4 filtering rules \n ");
+
+	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+	{
+		if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+	}
+	IPACMDBG_H("Finished delete default iface ipv6 filtering rules \n ");
+
+	if (ip_type != IPA_IP_v6)
+	{
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+				== false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+	IPACMDBG_H("Finished delete default iface ipv4 rules \n ");
+
+	/* delete default v6 routing rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		/* may have multiple ipv6 iface-RT rules*/
+		for (i = 0; i < 2*num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + i], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+
+	IPACMDBG_H("Finished delete default iface ipv6 rules \n ");
+
+	/* free the edm clients cache */
+	IPACMDBG_H("Free ecm clients cache\n");
+
+	/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule */
+	IPACMDBG_H("dev %s delete producer dependency\n", dev_name);
+	if (tx_prop != NULL)
+	{
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+	}
+
+	eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL);
+
+/* Delete private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+		IPACMDBG_H(" Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		if(IPACM_Iface::ipacmcfg->DelPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+		{
+			IPACMERR(" can't Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		}
+	}
+
+	/* reset the IPA-client pipe enum */
+	if(ipa_if_cate != WAN_IF)
+	{
+		handle_tethering_client(true, IPACM_CLIENT_USB);
+	}
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+fail:
+	/* clean eth-client header, routing rules */
+	IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client);
+	for (i = 0; i < num_eth_client; i++)
+	{
+		/* First reset nat rules and then route rules */
+		if(get_client_memptr(eth_client, i)->ipv4_set == true)
+		{
+			IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, i)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, i)->v4_addr);
+		}
+
+		if (delete_eth_rtrules(i, IPA_IP_v4))
+		{
+			IPACMERR("unbale to delete ecm-client v4 route rules for index %d\n", i);
+			res = IPACM_FAILURE;
+		}
+
+		if (delete_eth_rtrules(i, IPA_IP_v6))
+		{
+			IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
+			res = IPACM_FAILURE;
+		}
+
+		IPACMDBG_H("Delete %d client header\n", num_eth_client);
+
+		if(get_client_memptr(eth_client, i)->ipv4_header_set == true)
+		{
+			if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v4)
+				== false)
+			{
+				res = IPACM_FAILURE;
+			}
+		}
+
+		if(get_client_memptr(eth_client, i)->ipv6_header_set == true)
+		{
+			if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v6)
+					== false)
+			{
+				res = IPACM_FAILURE;
+			}
+		}
+	} /* end of for loop */
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true && rx_prop != NULL)
+	{
+		handle_software_routing_disable();
+	}
+
+	if (odu_route_rule_v4_hdl != NULL)
+	{
+		free(odu_route_rule_v4_hdl);
+	}
+	if (odu_route_rule_v6_hdl != NULL)
+	{
+		free(odu_route_rule_v6_hdl);
+	}
+	/* Delete corresponding ipa_rm_resource_name of RX-endpoint after delete all IPV4V6 FT-rule */
+	if (rx_prop != NULL)
+	{
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+		IPACMDBG_H("Finished delete dependency \n ");
+		free(rx_prop);
+	}
+
+	if (eth_client != NULL)
+	{
+		free(eth_client);
+	}
+
+	if (tx_prop != NULL)
+	{
+		free(tx_prop);
+	}
+	if (iface_query != NULL)
+	{
+		free(iface_query);
+	}
+
+	is_active = false;
+	post_del_self_evt();
+
+	return res;
+}
+
+/* install UL filter rule from Q6 */
+int IPACM_Lan::handle_uplink_filter_rule(ipacm_ext_prop *prop, ipa_ip_type iptype, uint8_t xlat_mux_id)
+{
+	ipa_flt_rule_add flt_rule_entry;
+	int len = 0, cnt, ret = IPACM_SUCCESS;
+	ipa_ioc_add_flt_rule *pFilteringTable;
+	ipa_fltr_installed_notif_req_msg_v01 flt_index;
+	int fd;
+	int i, index;
+	uint32_t value = 0;
+
+	IPACMDBG_H("Set modem UL flt rules\n");
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(prop == NULL || prop->num_ext_props <= 0)
+	{
+		IPACMDBG_H("No extended property.\n");
+		return IPACM_SUCCESS;
+	}
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+	if (prop->num_ext_props > MAX_WAN_UL_FILTER_RULES)
+	{
+		IPACMERR("number of modem UL rules > MAX_WAN_UL_FILTER_RULES, aborting...\n");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+
+	memset(&flt_index, 0, sizeof(flt_index));
+	flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+	flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+	flt_index.filter_index_list_len = prop->num_ext_props;
+#else /* defined (FEATURE_IPA_V3) */
+	flt_index.rule_id_valid = 1;
+	flt_index.rule_id_len = prop->num_ext_props;
+#endif
+	flt_index.embedded_pipe_index_valid = 1;
+	flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+	flt_index.retain_header_valid = 1;
+	flt_index.retain_header = 0;
+	flt_index.embedded_call_mux_id_valid = 1;
+	flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
+#ifndef FEATURE_IPA_V3
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#else /* defined (FEATURE_IPA_V3) */
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.rule_id_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#endif
+	len = sizeof(struct ipa_ioc_add_flt_rule) + prop->num_ext_props * sizeof(struct ipa_flt_rule_add);
+	pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	pFilteringTable->global = false;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->num_rules = prop->num_ext_props;
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+	flt_rule_entry.at_rear = 1;
+#ifdef FEATURE_IPA_V3
+	if (flt_rule_entry.rule.eq_attrib.ipv4_frag_eq_present)
+		flt_rule_entry.at_rear = 0;
+#endif
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 1;
+	if(iptype == IPA_IP_v4)
+	{
+		if (ipa_if_cate == ODU_IF && IPACM_Wan::isWan_Bridge_Mode())
+		{
+			IPACMDBG_H("WAN, ODU are in bridge mode \n");
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		}
+		else
+		{
+			flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		}
+	}
+	else if(iptype == IPA_IP_v6)
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+	else
+	{
+		IPACMERR("IP type is not expected.\n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+
+	index = IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, iptype);
+
+	for(cnt=0; cnt<prop->num_ext_props; cnt++)
+	{
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &prop->prop[cnt].eq_attrib,
+					 sizeof(prop->prop[cnt].eq_attrib));
+		flt_rule_entry.rule.rt_tbl_idx = prop->prop[cnt].rt_tbl_idx;
+
+		/* Handle XLAT configuration */
+		if ((iptype == IPA_IP_v4) && prop->prop[cnt].is_xlat_rule && (xlat_mux_id != 0))
+		{
+			/* fill the value of meta-data */
+			value = xlat_mux_id;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.value = (value & 0xFF) << 16;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.mask = 0x00FF0000;
+			IPACMDBG_H("xlat meta-data is modified for rule: %d has index %d with xlat_mux_id: %d\n",
+					cnt, index, xlat_mux_id);
+		}
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = prop->prop[cnt].is_rule_hashable;
+		flt_rule_entry.rule.rule_id = prop->prop[cnt].rule_id;
+		if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)	//turn on meta-data equation
+		{
+			flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+			flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.value |= rx_prop->rx[0].attrib.meta_data;
+			flt_rule_entry.rule.eq_attrib.metadata_meq32.mask |= rx_prop->rx[0].attrib.meta_data_mask;
+		}
+#endif
+		memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
+
+		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+#ifndef FEATURE_IPA_V3
+		flt_index.filter_index_list[cnt].filter_index = index;
+		flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id[cnt] = prop->prop[cnt].rule_id;
+#endif
+		index++;
+	}
+
+	if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+	{
+		IPACMERR("Error sending filtering rule index, aborting...\n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+
+	if(false == m_filtering.AddFilteringRule(pFilteringTable))
+	{
+		IPACMERR("Error Adding RuleTable to Filtering, aborting...\n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+	else
+	{
+		if(iptype == IPA_IP_v4)
+		{
+			for(i=0; i<pFilteringTable->num_rules; i++)
+			{
+				wan_ul_fl_rule_hdl_v4[num_wan_ul_fl_rule_v4] = pFilteringTable->rules[i].flt_rule_hdl;
+				num_wan_ul_fl_rule_v4++;
+			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
+		}
+		else if(iptype == IPA_IP_v6)
+		{
+			for(i=0; i<pFilteringTable->num_rules; i++)
+			{
+				wan_ul_fl_rule_hdl_v6[num_wan_ul_fl_rule_v6] = pFilteringTable->rules[i].flt_rule_hdl;
+				num_wan_ul_fl_rule_v6++;
+			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
+		}
+		else
+		{
+			IPACMERR("IP type is not expected.\n");
+			goto fail;
+		}
+	}
+
+fail:
+	free(pFilteringTable);
+	close(fd);
+	return ret;
+}
+
+int IPACM_Lan::handle_wan_down_v6(bool is_sta_mode)
+{
+	ipa_fltr_installed_notif_req_msg_v01 flt_index;
+	int fd;
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+	delete_ipv6_prefix_flt_rule();
+
+	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+
+	if(is_sta_mode == false)
+	{
+		if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
+		{
+			IPACMERR(" the number of rules (%d) are bigger than array (%d), aborting...\n", num_wan_ul_fl_rule_v6, MAX_WAN_UL_FILTER_RULES);
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		if (num_wan_ul_fl_rule_v6 == 0)
+		{
+			IPACMERR("No modem UL rules were installed, return...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+
+		if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v6,
+			IPA_IP_v6, num_wan_ul_fl_rule_v6) == false)
+		{
+			IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_wan_ul_fl_rule_v6);
+		memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+		num_wan_ul_fl_rule_v6 = 0;
+		modem_ul_v6_set = false;
+
+		memset(&flt_index, 0, sizeof(flt_index));
+		flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+		flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+		flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id_valid = 1;
+		flt_index.rule_id_len = 0;
+#endif
+		flt_index.embedded_pipe_index_valid = 1;
+		flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+		flt_index.retain_header_valid = 1;
+		flt_index.retain_header = 0;
+		flt_index.embedded_call_mux_id_valid = 1;
+		flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
+		if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+		{
+			IPACMERR("Error sending filtering rule index, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		if (m_filtering.DeleteFilteringHdls(&dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES],
+																				IPA_IP_v6, 1) == false)
+		{
+			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+	}
+	close(fd);
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::reset_to_dummy_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl)
+{
+	int len, res = IPACM_SUCCESS;
+	struct ipa_flt_rule_mdfy flt_rule;
+	struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+	IPACMDBG_H("Reset flt rule to dummy, IP type: %d, hdl: %d\n", iptype, rule_hdl);
+	len = sizeof(struct ipa_ioc_mdfy_flt_rule) + sizeof(struct ipa_flt_rule_mdfy);
+	pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error allocate flt rule memory...\n");
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->num_rules = 1;
+
+	memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
+	flt_rule.status = -1;
+	flt_rule.rule_hdl = rule_hdl;
+
+	flt_rule.rule.retain_hdr = 0;
+	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+
+	if(iptype == IPA_IP_v4)
+	{
+		IPACMDBG_H("Reset IPv4 flt rule to dummy\n");
+
+		flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+		flt_rule.rule.attrib.u.v4.dst_addr = ~0;
+		flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
+		flt_rule.rule.attrib.u.v4.src_addr = ~0;
+		flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
+
+		memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+		if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+		{
+			IPACMERR("Error modifying filtering rule.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			IPACMDBG_H("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
+						pFilteringTable->rules[0].status);
+		}
+	}
+	else if(iptype == IPA_IP_v6)
+	{
+		IPACMDBG_H("Reset IPv6 flt rule to dummy\n");
+
+		flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+		flt_rule.rule.attrib.u.v6.src_addr[0] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr[1] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr[2] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr[3] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr_mask[0] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr_mask[1] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr_mask[2] = ~0;
+		flt_rule.rule.attrib.u.v6.src_addr_mask[3] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr[0] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr[1] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr[2] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr[3] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = ~0;
+		flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = ~0;
+
+
+		memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+		if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+		{
+			IPACMERR("Error modifying filtering rule.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			IPACMDBG_H("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
+						pFilteringTable->rules[0].status);
+		}
+	}
+	else
+	{
+		IPACMERR("IP type is not expected.\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+
+fail:
+	free(pFilteringTable);
+	return res;
+}
+
+void IPACM_Lan::post_del_self_evt()
+{
+	ipacm_cmd_q_data evt;
+	ipacm_event_data_fid* fid;
+	fid = (ipacm_event_data_fid*)malloc(sizeof(ipacm_event_data_fid));
+	if(fid == NULL)
+	{
+		IPACMERR("Failed to allocate fid memory.\n");
+		return;
+	}
+	memset(fid, 0, sizeof(ipacm_event_data_fid));
+	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
+
+	fid->if_index = ipa_if_num;
+
+	evt.evt_data = (void*)fid;
+	evt.event = IPA_LAN_DELETE_SELF;
+
+	IPACMDBG_H("Posting event IPA_LAN_DELETE_SELF\n");
+	IPACM_EvtDispatcher::PostEvt(&evt);
+}
+
+/*handle reset usb-client rt-rules */
+int IPACM_Lan::handle_lan_client_reset_rt(ipa_ip_type iptype)
+{
+	int i, res = IPACM_SUCCESS;
+
+	/* clean eth-client routing rules */
+	IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client);
+	for (i = 0; i < num_eth_client; i++)
+	{
+		res = delete_eth_rtrules(i, iptype);
+		if (res != IPACM_SUCCESS)
+		{
+			IPACMERR("Failed to delete old iptype(%d) rules.\n", iptype);
+			return res;
+		}
+	} /* end of for loop */
+
+	/* Reset ip-address */
+	for (i = 0; i < num_eth_client; i++)
+	{
+		if(iptype == IPA_IP_v4)
+		{
+			get_client_memptr(eth_client, i)->ipv4_set = false;
+		}
+		else
+		{
+			get_client_memptr(eth_client, i)->ipv6_set = 0;
+		}
+	} /* end of for loop */
+	return res;
+}
+
+int IPACM_Lan::install_ipv4_icmp_flt_rule()
+{
+	int len;
+	struct ipa_ioc_add_flt_rule* flt_rule;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	if(rx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+		flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!flt_rule)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		flt_rule->commit = 1;
+		flt_rule->ep = rx_prop->rx[0].src_pipe;
+		flt_rule->global = false;
+		flt_rule->ip = IPA_IP_v4;
+		flt_rule->num_rules = 1;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 0;
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
+		memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (m_filtering.AddFilteringRule(flt_rule) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			free(flt_rule);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+			ipv4_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+			IPACMDBG_H("IPv4 icmp filter rule HDL:0x%x\n", ipv4_icmp_flt_rule_hdl[0]);
+                        free(flt_rule);
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::install_ipv6_icmp_flt_rule()
+{
+
+	int len;
+	struct ipa_ioc_add_flt_rule* flt_rule;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	if(rx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+		flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!flt_rule)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		flt_rule->commit = 1;
+		flt_rule->ep = rx_prop->rx[0].src_pipe;
+		flt_rule->global = false;
+		flt_rule->ip = IPA_IP_v6;
+		flt_rule->num_rules = 1;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 0;
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = false;
+#endif
+		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+		flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+		memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (m_filtering.AddFilteringRule(flt_rule) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			free(flt_rule);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+			ipv6_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+			IPACMDBG_H("IPv6 icmp filter rule HDL:0x%x\n", ipv6_icmp_flt_rule_hdl[0]);
+			free(flt_rule);
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::add_dummy_private_subnet_flt_rule(ipa_ip_type iptype)
+{
+	if(rx_prop == NULL)
+	{
+		IPACMDBG_H("There is no rx_prop for iface %s, not able to add dummy private subnet filtering rule.\n", dev_name);
+		return 0;
+	}
+
+	if(iptype == IPA_IP_v6)
+	{
+		IPACMDBG_H("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
+		return 0;
+	}
+	int i, len, res = IPACM_SUCCESS;
+	struct ipa_flt_rule_add flt_rule;
+	ipa_ioc_add_flt_rule* pFilteringTable;
+
+	len = sizeof(struct ipa_ioc_add_flt_rule) +	IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(struct ipa_flt_rule_add);
+
+	pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error allocate flt table memory...\n");
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	pFilteringTable->global = false;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->num_rules = IPA_MAX_PRIVATE_SUBNET_ENTRIES;
+
+	memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
+
+	flt_rule.rule.retain_hdr = 0;
+	flt_rule.at_rear = true;
+	flt_rule.flt_rule_hdl = -1;
+	flt_rule.status = -1;
+	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+	flt_rule.rule.hashable = true;
+#endif
+	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
+			sizeof(flt_rule.rule.attrib));
+
+	if(iptype == IPA_IP_v4)
+	{
+		flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+		flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
+		flt_rule.rule.attrib.u.v4.src_addr = ~0;
+		flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
+		flt_rule.rule.attrib.u.v4.dst_addr = ~0;
+
+		for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+		{
+			memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_add));
+		}
+
+		if (false == m_filtering.AddFilteringRule(pFilteringTable))
+		{
+			IPACMERR("Error adding dummy private subnet v4 flt rule\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+			/* copy filter rule hdls */
+			for (int i = 0; i < IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+			{
+				if (pFilteringTable->rules[i].status == 0)
+				{
+					private_fl_rule_hdl[i] = pFilteringTable->rules[i].flt_rule_hdl;
+					IPACMDBG_H("Private subnet v4 flt rule %d hdl:0x%x\n", i, private_fl_rule_hdl[i]);
+				}
+				else
+				{
+					IPACMERR("Failed adding lan2lan v4 flt rule %d\n", i);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+			}
+		}
+	}
+fail:
+	free(pFilteringTable);
+	return res;
+}
+
+int IPACM_Lan::handle_private_subnet_android(ipa_ip_type iptype)
+{
+	int i, len, res = IPACM_SUCCESS;
+	struct ipa_flt_rule_mdfy flt_rule;
+	struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(iptype == IPA_IP_v6)
+	{
+		IPACMDBG_H("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
+		return 0;
+	}
+	else
+	{
+		for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+		{
+			reset_to_dummy_flt_rule(IPA_IP_v4, private_fl_rule_hdl[i]);
+		}
+
+		len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_mdfy);
+		pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+		if (!pFilteringTable)
+		{
+			IPACMERR("Failed to allocate ipa_ioc_mdfy_flt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+		memset(pFilteringTable, 0, len);
+
+		pFilteringTable->commit = 1;
+		pFilteringTable->ip = iptype;
+		pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+		/* Make LAN-traffic always go A5, use default IPA-RT table */
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
+		{
+			IPACMERR("Failed to get routing table handle.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
+		flt_rule.status = -1;
+
+		flt_rule.rule.retain_hdr = 1;
+		flt_rule.rule.to_uc = 0;
+		flt_rule.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule.rule.eq_attrib_type = 0;
+		flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
+		IPACMDBG_H("Private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
+
+		memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
+		flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+		{
+			flt_rule.rule_hdl = private_fl_rule_hdl[i];
+			flt_rule.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+			flt_rule.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+			memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+			IPACMDBG_H(" IPACM private subnet_addr as: 0x%x entry(%d)\n", flt_rule.rule.attrib.u.v4.dst_addr, i);
+		}
+
+		if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+		{
+			IPACMERR("Failed to modify private subnet filtering rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+fail:
+	if(pFilteringTable != NULL)
+	{
+		free(pFilteringTable);
+	}
+	return res;
+}
+
+int IPACM_Lan::install_ipv6_prefix_flt_rule(uint32_t* prefix)
+{
+	if(prefix == NULL)
+	{
+		IPACMERR("IPv6 prefix is empty.\n");
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("Receive IPv6 prefix: 0x%08x%08x.\n", prefix[0], prefix[1]);
+
+	int len;
+	struct ipa_ioc_add_flt_rule* flt_rule;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	if(rx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+		flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!flt_rule)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		flt_rule->commit = 1;
+		flt_rule->ep = rx_prop->rx[0].src_pipe;
+		flt_rule->global = false;
+		flt_rule->ip = IPA_IP_v6;
+		flt_rule->num_rules = 1;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 0;
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = prefix[0];
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = prefix[1];
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x0;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x0;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x0;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x0;
+		memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (m_filtering.AddFilteringRule(flt_rule) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			free(flt_rule);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+			ipv6_prefix_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+			IPACMDBG_H("IPv6 prefix filter rule HDL:0x%x\n", ipv6_prefix_flt_rule_hdl[0]);
+			free(flt_rule);
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+void IPACM_Lan::delete_ipv6_prefix_flt_rule()
+{
+	if(m_filtering.DeleteFilteringHdls(ipv6_prefix_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE) == false)
+	{
+		IPACMERR("Failed to delete ipv6 prefix flt rule.\n");
+		return;
+	}
+	IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE);
+	return;
+}
+
+int IPACM_Lan::handle_addr_evt_odu_bridge(ipacm_event_data_addr* data)
+{
+	int fd, res = IPACM_SUCCESS;
+	struct in6_addr ipv6_addr;
+	if(data == NULL)
+	{
+		IPACMERR("Failed to get interface IP address.\n");
+		return IPACM_FAILURE;
+	}
+
+	if(data->iptype == IPA_IP_v6)
+	{
+		fd = open(IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU, O_RDWR);
+		if(fd == 0)
+		{
+			IPACMERR("Failed to open %s.\n", IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU);
+			return IPACM_FAILURE;
+		}
+
+		memcpy(&ipv6_addr, data->ipv6_addr, sizeof(struct in6_addr));
+
+		if( ioctl(fd, ODU_BRIDGE_IOC_SET_LLV6_ADDR, &ipv6_addr) )
+		{
+			IPACMERR("Failed to write IPv6 address to odu driver.\n");
+			res = IPACM_FAILURE;
+		}
+		num_dft_rt_v6++;
+		close(fd);
+	}
+
+	return res;
+}
+
+ipa_hdr_proc_type IPACM_Lan::eth_bridge_get_hdr_proc_type(ipa_hdr_l2_type t1, ipa_hdr_l2_type t2)
+{
+	if(t1 == IPA_HDR_L2_ETHERNET_II)
+	{
+		if(t2 == IPA_HDR_L2_ETHERNET_II)
+		{
+			return IPA_HDR_PROC_ETHII_TO_ETHII;
+		}
+		if(t2 == IPA_HDR_L2_802_3)
+		{
+			return IPA_HDR_PROC_ETHII_TO_802_3;
+		}
+	}
+
+	if(t1 == IPA_HDR_L2_802_3)
+	{
+		if(t2 == IPA_HDR_L2_ETHERNET_II)
+		{
+			return IPA_HDR_PROC_802_3_TO_ETHII;
+		}
+		if(t2 == IPA_HDR_L2_802_3)
+		{
+			return IPA_HDR_PROC_802_3_TO_802_3;
+		}
+	}
+
+	return IPA_HDR_PROC_NONE;
+}
+
+int IPACM_Lan::eth_bridge_get_hdr_template_hdl(uint32_t* hdr_hdl)
+{
+	if(hdr_hdl == NULL)
+	{
+		IPACMDBG_H("Hdr handle pointer is empty.\n");
+		return IPACM_FAILURE;
+	}
+
+	struct ipa_ioc_get_hdr hdr;
+	memset(&hdr, 0, sizeof(hdr));
+
+	memcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+	if(m_header.GetHeaderHandle(&hdr) == false)
+	{
+		IPACMERR("Failed to get template hdr hdl.\n");
+		return IPACM_FAILURE;
+	}
+
+	*hdr_hdl = hdr.hdl;
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::handle_cradle_wan_mode_switch(bool is_wan_bridge_mode)
+{
+	struct ipa_flt_rule_mdfy flt_rule_entry;
+	int len = 0;
+	ipa_ioc_mdfy_flt_rule *m_pFilteringTable;
+
+	IPACMDBG_H("Handle wan mode swtich: is wan bridge mode?%d\n", is_wan_bridge_mode);
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (1 * sizeof(struct ipa_flt_rule_mdfy));
+	m_pFilteringTable = (struct ipa_ioc_mdfy_flt_rule *)calloc(1, len);
+	if (m_pFilteringTable == NULL)
+	{
+		PERROR("Error Locate ipa_ioc_mdfy_flt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ip = IPA_IP_v4;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+	IPACMDBG_H("Retrieving routing hanle for table: %s\n",
+					 IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+	if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+	{
+		IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+						 &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("Routing handle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_mdfy)); // Zero All Fields
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule_hdl = lan_wan_fl_rule_hdl[0];
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 0;
+	if(is_wan_bridge_mode)
+	{
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+	}
+	else
+	{
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+	}
+	flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+	memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+	if (false == m_filtering.ModifyFilteringRule(m_pFilteringTable))
+	{
+		IPACMERR("Error Modifying RuleTable(0) to Filtering, aborting...\n");
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		IPACMDBG_H("flt rule hdl = %d, status = %d\n",
+						 m_pFilteringTable->rules[0].rule_hdl,
+						 m_pFilteringTable->rules[0].status);
+	}
+	free(m_pFilteringTable);
+	return IPACM_SUCCESS;
+}
+
+/*handle reset usb-client rt-rules */
+int IPACM_Lan::handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data)
+{
+	int cnt, pipe_len, fd;
+	uint64_t num_ul_packets, num_ul_bytes;
+	uint64_t num_dl_packets, num_dl_bytes;
+	bool ul_pipe_found, dl_pipe_found;
+	FILE *fp = NULL;
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+
+	ul_pipe_found = false;
+	dl_pipe_found = false;
+	num_ul_packets = 0;
+	num_dl_packets = 0;
+	num_ul_bytes = 0;
+	num_dl_bytes = 0;
+
+	if (data->dl_dst_pipe_stats_list_valid)
+	{
+		if(tx_prop != NULL)
+		{
+			for (pipe_len = 0; pipe_len < data->dl_dst_pipe_stats_list_len; pipe_len++)
+			{
+				IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->dl_dst_pipe_stats_list[pipe_len].pipe_index);
+				for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+				{
+					IPACMDBG_H("Check Tx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe));
+					if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe) == data->dl_dst_pipe_stats_list[pipe_len].pipe_index)
+					{
+						/* update the DL stats */
+						dl_pipe_found = true;
+						num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_packets;
+						num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_packets;
+						num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_bytes;
+						num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_bytes;
+						IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->dl_dst_pipe_stats_list[pipe_len].pipe_index, cnt);
+						IPACMDBG_H("DL_packets:(%lu) DL_bytes:(%lu) \n", num_dl_packets, num_dl_bytes);
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	if (data->ul_src_pipe_stats_list_valid)
+	{
+		if(rx_prop != NULL)
+		{
+			for (pipe_len = 0; pipe_len < data->ul_src_pipe_stats_list_len; pipe_len++)
+			{
+				IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->ul_src_pipe_stats_list[pipe_len].pipe_index);
+				for (cnt=0; cnt < rx_prop->num_rx_props; cnt++)
+				{
+					IPACMDBG_H("Check Rx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe));
+					if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe) == data->ul_src_pipe_stats_list[pipe_len].pipe_index)
+					{
+						/* update the UL stats */
+						ul_pipe_found = true;
+						num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_packets;
+						num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_packets;
+						num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_bytes;
+						num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_bytes;
+						IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->ul_src_pipe_stats_list[pipe_len].pipe_index, cnt);
+						IPACMDBG_H("UL_packets:(%lu) UL_bytes:(%lu) \n", num_ul_packets, num_ul_bytes);
+						break;
+					}
+				}
+			}
+		}
+	}
+	close(fd);
+
+	if (ul_pipe_found || dl_pipe_found)
+	{
+		IPACMDBG_H("Update IPA_TETHERING_STATS_UPDATE_EVENT, TX(P%lu/B%lu) RX(P%lu/B%lu) DEV(%s) to LTE(%s) \n",
+					num_ul_packets,
+						num_ul_bytes,
+							num_dl_packets,
+								num_dl_bytes,
+									dev_name,
+										IPACM_Wan::wan_up_dev_name);
+		fp = fopen(IPA_PIPE_STATS_FILE_NAME, "w");
+		if ( fp == NULL )
+		{
+			IPACMERR("Failed to write pipe stats to %s, error is %d - %s\n",
+					IPA_PIPE_STATS_FILE_NAME, errno, strerror(errno));
+			return IPACM_FAILURE;
+		}
+
+		fprintf(fp, PIPE_STATS,
+				dev_name,
+					IPACM_Wan::wan_up_dev_name,
+						num_ul_bytes,
+						num_ul_packets,
+							    num_dl_bytes,
+							num_dl_packets);
+		fclose(fp);
+	}
+	return IPACM_SUCCESS;
+}
+
+/*handle tether client */
+int IPACM_Lan::handle_tethering_client(bool reset, ipacm_client_enum ipa_client)
+{
+	int cnt, fd, ret = IPACM_SUCCESS;
+	int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+	wan_ioctl_set_tether_client_pipe tether_client;
+
+	if(fd_wwan_ioctl < 0)
+	{
+		IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		close(fd_wwan_ioctl);
+		return IPACM_FAILURE;
+	}
+
+	memset(&tether_client, 0, sizeof(tether_client));
+	tether_client.reset_client = reset;
+	tether_client.ipa_client = ipa_client;
+
+	if(tx_prop != NULL)
+	{
+		tether_client.dl_dst_pipe_len = tx_prop->num_tx_props;
+		for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
+		{
+			IPACMDBG_H("Tx(%d), dst_pipe: %d, ipa_pipe: %d\n",
+					cnt, tx_prop->tx[cnt].dst_pipe,
+						ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe));
+			tether_client.dl_dst_pipe_list[cnt] = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe);
+		}
+	}
+
+	if(rx_prop != NULL)
+	{
+		tether_client.ul_src_pipe_len = rx_prop->num_rx_props;
+		for (cnt = 0; cnt < rx_prop->num_rx_props; cnt++)
+		{
+			IPACMDBG_H("Rx(%d), src_pipe: %d, ipa_pipe: %d\n",
+					cnt, rx_prop->rx[cnt].src_pipe,
+						ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe));
+			tether_client.ul_src_pipe_list[cnt] = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe);
+		}
+	}
+
+	ret = ioctl(fd_wwan_ioctl, WAN_IOC_SET_TETHER_CLIENT_PIPE, &tether_client);
+	if (ret != 0)
+	{
+		IPACMERR("Failed set tether-client-pipe %p with ret %d\n ", &tether_client, ret);
+	}
+	IPACMDBG("Set tether-client-pipe %p\n", &tether_client);
+	close(fd);
+	close(fd_wwan_ioctl);
+	return ret;
+}
+
+/* mac address has to be provided for client related events */
+void IPACM_Lan::eth_bridge_post_event(ipa_cm_event_id evt, ipa_ip_type iptype, uint8_t *mac)
+{
+	ipacm_cmd_q_data eth_bridge_evt;
+	ipacm_event_eth_bridge *evt_data;
+
+	evt_data = (ipacm_event_eth_bridge*)malloc(sizeof(ipacm_event_eth_bridge));
+	if(evt_data == NULL)
+	{
+		IPACMERR("Failed to allocate memory.\n");
+		return;
+	}
+	memset(evt_data, 0, sizeof(ipacm_event_eth_bridge));
+
+	evt_data->p_iface = this;
+	evt_data->iptype = iptype;
+	if(mac)
+	{
+		IPACMDBG_H("Client mac: 0x%02x%02x%02x%02x%02x%02x \n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		memcpy(evt_data->mac_addr, mac, sizeof(evt_data->mac_addr));
+	}
+
+	memset(&eth_bridge_evt, 0, sizeof(ipacm_cmd_q_data));
+	eth_bridge_evt.evt_data = (void*)evt_data;
+	eth_bridge_evt.event = evt;
+
+	IPACMDBG_H("Posting event %s\n",
+		IPACM_Iface::ipacmcfg->getEventName(evt));
+	IPACM_EvtDispatcher::PostEvt(&eth_bridge_evt);
+}
+
+/* add header processing context and return handle to lan2lan controller */
+int IPACM_Lan::eth_bridge_add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_hdr_type, uint32_t *hdl)
+{
+	int len, res = IPACM_SUCCESS;
+	uint32_t hdr_template;
+	ipa_ioc_add_hdr_proc_ctx* pHeaderProcTable = NULL;
+
+	if(tx_prop == NULL)
+	{
+		IPACMERR("No tx prop.\n");
+		return IPACM_FAILURE;
+	}
+
+	len = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_add);
+	pHeaderProcTable = (ipa_ioc_add_hdr_proc_ctx*)malloc(len);
+	if(pHeaderProcTable == NULL)
+	{
+		IPACMERR("Cannot allocate header processing context table.\n");
+		return IPACM_FAILURE;
+	}
+
+	memset(pHeaderProcTable, 0, len);
+	pHeaderProcTable->commit = 1;
+	pHeaderProcTable->num_proc_ctxs = 1;
+	pHeaderProcTable->proc_ctx[0].type = eth_bridge_get_hdr_proc_type(peer_l2_hdr_type, tx_prop->tx[0].hdr_l2_type);
+	eth_bridge_get_hdr_template_hdl(&hdr_template);
+	pHeaderProcTable->proc_ctx[0].hdr_hdl = hdr_template;
+	if (m_header.AddHeaderProcCtx(pHeaderProcTable) == false)
+	{
+		IPACMERR("Adding hdr proc ctx failed with status: %d\n", pHeaderProcTable->proc_ctx[0].status);
+		res = IPACM_FAILURE;
+		goto end;
+	}
+
+	*hdl = pHeaderProcTable->proc_ctx[0].proc_ctx_hdl;
+
+end:
+	free(pHeaderProcTable);
+	return res;
+}
+
+/* add routing rule and return handle to lan2lan controller */
+int IPACM_Lan::eth_bridge_add_rt_rule(uint8_t *mac, char *rt_tbl_name, uint32_t hdr_proc_ctx_hdl,
+		ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int *rt_rule_count)
+{
+	int i, len, res = IPACM_SUCCESS;
+	struct ipa_ioc_add_rt_rule* rt_rule_table = NULL;
+	struct ipa_rt_rule_add rt_rule;
+	int position, num_rt_rule;
+
+	IPACMDBG_H("Received client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	num_rt_rule = each_client_rt_rule_count[iptype];
+
+	len = sizeof(ipa_ioc_add_rt_rule) + num_rt_rule * sizeof(ipa_rt_rule_add);
+	rt_rule_table = (ipa_ioc_add_rt_rule*)malloc(len);
+	if (rt_rule_table == NULL)
+	{
+		IPACMERR("Failed to allocate memory.\n");
+		return IPACM_FAILURE;
+	}
+	memset(rt_rule_table, 0, len);
+
+	rt_rule_table->commit = 1;
+	rt_rule_table->ip = iptype;
+	rt_rule_table->num_rules = num_rt_rule;
+	strlcpy(rt_rule_table->rt_tbl_name, rt_tbl_name, sizeof(rt_rule_table->rt_tbl_name));
+	rt_rule_table->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = 0;
+
+	memset(&rt_rule, 0, sizeof(ipa_rt_rule_add));
+	rt_rule.at_rear = false;
+	rt_rule.status = -1;
+	rt_rule.rt_rule_hdl = -1;
+#ifdef FEATURE_IPA_V3
+	rt_rule.rule.hashable = true;
+#endif
+	rt_rule.rule.hdr_hdl = 0;
+	rt_rule.rule.hdr_proc_ctx_hdl = hdr_proc_ctx_hdl;
+
+	position = 0;
+	for(i=0; i<iface_query->num_tx_props; i++)
+	{
+		if(tx_prop->tx[i].ip == iptype)
+		{
+			if(position >= num_rt_rule || position >= MAX_NUM_PROP)
+			{
+				IPACMERR("Number of routing rules already exceeds limit.\n");
+				res = IPACM_FAILURE;
+				goto end;
+			}
+
+			if(ipa_if_cate == WLAN_IF && IPACM_Iface::ipacmcfg->isMCC_Mode)
+			{
+				IPACMDBG_H("In WLAN MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[i].alt_dst_pipe);
+				rt_rule.rule.dst = tx_prop->tx[i].alt_dst_pipe;
+			}
+			else
+			{
+				IPACMDBG_H("It is not WLAN MCC mode, use dst pipe: %d\n",
+						tx_prop->tx[i].dst_pipe);
+				rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
+			}
+
+			memcpy(&rt_rule.rule.attrib, &tx_prop->tx[i].attrib, sizeof(rt_rule.rule.attrib));
+			if(peer_l2_hdr_type == IPA_HDR_L2_ETHERNET_II)
+				rt_rule.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+			else
+				rt_rule.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+			memcpy(rt_rule.rule.attrib.dst_mac_addr, mac, sizeof(rt_rule.rule.attrib.dst_mac_addr));
+			memset(rt_rule.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(rt_rule.rule.attrib.dst_mac_addr_mask));
+
+			memcpy(&(rt_rule_table->rules[position]), &rt_rule, sizeof(rt_rule_table->rules[position]));
+			position++;
+		}
+	}
+	if(false == m_routing.AddRoutingRule(rt_rule_table))
+	{
+		IPACMERR("Routing rule addition failed!\n");
+		res = IPACM_FAILURE;
+		goto end;
+	}
+	else
+	{
+		*rt_rule_count = position;
+		for(i=0; i<position; i++)
+			rt_rule_hdl[i] = rt_rule_table->rules[i].rt_rule_hdl;
+	}
+
+end:
+	free(rt_rule_table);
+	return res;
+}
+
+/* modify routing rule*/
+int IPACM_Lan::eth_bridge_modify_rt_rule(uint8_t *mac, uint32_t hdr_proc_ctx_hdl,
+		ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int rt_rule_count)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	int len, index, res = IPACM_SUCCESS;
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties \n");
+		return IPACM_FAILURE;
+	}
+
+	if(ipa_if_cate != WLAN_IF)
+	{
+		IPACMDBG_H("This is not WLAN IF, no need to modify rt rule.\n");
+		return IPACM_SUCCESS;
+	}
+
+	IPACMDBG_H("Receive WLAN client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	len = sizeof(struct ipa_ioc_mdfy_rt_rule) + rt_rule_count * sizeof(struct ipa_rt_rule_mdfy);
+	rt_rule = (struct ipa_ioc_mdfy_rt_rule *)malloc(len);
+	if(rt_rule == NULL)
+	{
+		IPACMERR("Unable to allocate memory for modify rt rule\n");
+		return IPACM_FAILURE;
+	}
+	memset(rt_rule, 0, len);
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = 0;
+	rt_rule->ip = iptype;
+
+	for (index = 0; index < tx_prop->num_tx_props; index++)
+	{
+		if (tx_prop->tx[index].ip == iptype)
+		{
+			if (rt_rule->num_rules >= rt_rule_count ||
+				rt_rule->num_rules >= MAX_NUM_PROP)
+			{
+				IPACMERR("Number of routing rules exceeds limit.\n");
+				res = IPACM_FAILURE;
+				goto end;
+			}
+
+			rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+			{
+				IPACMDBG_H("In WLAN MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[index].alt_dst_pipe);
+				rt_rule_entry->rule.dst = tx_prop->tx[index].alt_dst_pipe;
+			}
+			else
+			{
+				IPACMDBG_H("In WLAN SCC mode, use dst pipe: %d\n",
+						tx_prop->tx[index].dst_pipe);
+				rt_rule_entry->rule.dst = tx_prop->tx[index].dst_pipe;
+			}
+
+			rt_rule_entry->rule.hdr_hdl = 0;
+			rt_rule_entry->rule.hdr_proc_ctx_hdl = hdr_proc_ctx_hdl;
+#ifdef FEATURE_IPA_V3
+			rt_rule_entry->rule.hashable = true;
+#endif
+			memcpy(&rt_rule_entry->rule.attrib, &tx_prop->tx[index].attrib,
+					sizeof(rt_rule_entry->rule.attrib));
+			if(peer_l2_hdr_type == IPA_HDR_L2_ETHERNET_II)
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+			else
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+			memcpy(rt_rule_entry->rule.attrib.dst_mac_addr, mac,
+					sizeof(rt_rule_entry->rule.attrib.dst_mac_addr));
+			memset(rt_rule_entry->rule.attrib.dst_mac_addr_mask, 0xFF,
+					sizeof(rt_rule_entry->rule.attrib.dst_mac_addr_mask));
+
+			rt_rule_entry->rt_rule_hdl = rt_rule_hdl[rt_rule->num_rules];
+			rt_rule->num_rules++;
+		}
+	}
+
+	if(m_routing.ModifyRoutingRule(rt_rule) == false)
+	{
+		IPACMERR("Failed to modify routing rules.\n");
+		res = IPACM_FAILURE;
+		goto end;
+	}
+	if(m_routing.Commit(iptype) == false)
+	{
+		IPACMERR("Failed to commit routing rules.\n");
+		res = IPACM_FAILURE;
+		goto end;
+	}
+	IPACMDBG("Modified routing rules successfully.\n");
+
+end:
+	free(rt_rule);
+	return res;
+}
+
+int IPACM_Lan::eth_bridge_add_flt_rule(uint8_t *mac, uint32_t rt_tbl_hdl, ipa_ip_type iptype, uint32_t *flt_rule_hdl)
+{
+	int len, res = IPACM_SUCCESS;
+	struct ipa_flt_rule_add flt_rule_entry;
+	struct ipa_ioc_add_flt_rule_after *pFilteringTable = NULL;
+
+#ifdef FEATURE_IPA_V3
+	if (rx_prop == NULL || tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx or tx properties registered for iface %s\n", dev_name);
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG_H("Received client MAC 0x%02x%02x%02x%02x%02x%02x.\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	len = sizeof(struct ipa_ioc_add_flt_rule_after) + sizeof(struct ipa_flt_rule_add);
+	pFilteringTable = (struct ipa_ioc_add_flt_rule_after*)malloc(len);
+	if (!pFilteringTable)
+	{
+		IPACMERR("Failed to allocate ipa_ioc_add_flt_rule_after memory...\n");
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	/* add mac based rule*/
+	pFilteringTable->commit = 1;
+	pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->num_rules = 1;
+	pFilteringTable->add_after_hdl = eth_bridge_flt_rule_offset[iptype];
+
+	memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+	flt_rule_entry.at_rear = 1;
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+	flt_rule_entry.rule.eq_attrib_type = 0;
+	flt_rule_entry.rule.rt_tbl_hdl = rt_tbl_hdl;
+	flt_rule_entry.rule.hashable = true;
+
+	memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+	if(tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_ETHERNET_II)
+	{
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+	}
+	else
+	{
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+	}
+
+	memcpy(flt_rule_entry.rule.attrib.dst_mac_addr, mac, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr));
+	memset(flt_rule_entry.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask));
+
+	memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(flt_rule_entry));
+	if (false == m_filtering.AddFilteringRuleAfter(pFilteringTable))
+	{
+		IPACMERR("Failed to add client filtering rules.\n");
+		res = IPACM_FAILURE;
+		goto end;
+	}
+	*flt_rule_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+end:
+	free(pFilteringTable);
+#endif
+	return res;
+}
+
+int IPACM_Lan::eth_bridge_del_flt_rule(uint32_t flt_rule_hdl, ipa_ip_type iptype)
+{
+	if(m_filtering.DeleteFilteringHdls(&flt_rule_hdl, iptype, 1) == false)
+	{
+		IPACMERR("Failed to delete the client specific flt rule.\n");
+		return IPACM_FAILURE;
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::eth_bridge_del_rt_rule(uint32_t rt_rule_hdl, ipa_ip_type iptype)
+{
+	if(m_routing.DeleteRoutingHdl(rt_rule_hdl, iptype) == false)
+	{
+		IPACMERR("Failed to delete routing rule.\n");
+		return IPACM_FAILURE;
+	}
+	return IPACM_SUCCESS;
+}
+
+/* delete header processing context */
+int IPACM_Lan::eth_bridge_del_hdr_proc_ctx(uint32_t hdr_proc_ctx_hdl)
+{
+	if(m_header.DeleteHeaderProcCtx(hdr_proc_ctx_hdl) == false)
+	{
+		IPACMERR("Failed to delete hdr proc ctx.\n");
+		return IPACM_FAILURE;
+	}
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_LanToLan.cpp b/ipacm/src/IPACM_LanToLan.cpp
new file mode 100644
index 0000000..d77f389
--- /dev/null
+++ b/ipacm/src/IPACM_LanToLan.cpp
@@ -0,0 +1,1262 @@
+/*
+Copyright (c) 2014, 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_LanToLan.cpp
+
+	@brief
+	This file implements the functionality of offloading LAN to LAN traffic.
+
+	@Author
+	Shihuan Liu
+
+*/
+
+#include <stdlib.h>
+#include "IPACM_LanToLan.h"
+#include "IPACM_Wlan.h"
+
+#define __stringify(x...) #x
+
+const char *ipa_l2_hdr_type[] = {
+	__stringify(NONE),
+	__stringify(ETH_II),
+	__stringify(802_3),
+	__stringify(L2_MAX)
+};
+
+IPACM_LanToLan_Iface::IPACM_LanToLan_Iface(IPACM_Lan *p_iface)
+{
+	int i;
+
+	m_p_iface = p_iface;
+	memset(m_is_ip_addr_assigned, 0, sizeof(m_is_ip_addr_assigned));
+	m_support_inter_iface_offload = true;
+	m_support_intra_iface_offload = false;
+	for(i = 0; i < IPA_HDR_L2_MAX; i++)
+	{
+		ref_cnt_peer_l2_hdr_type[i] = 0;
+		hdr_proc_ctx_for_inter_interface[i] = 0;
+	}
+	hdr_proc_ctx_for_intra_interface = 0;
+
+	if(p_iface->ipa_if_cate == WLAN_IF)
+	{
+		IPACMDBG_H("Interface %s is WLAN interface.\n", p_iface->dev_name);
+		m_support_intra_iface_offload = true;
+		if( ((IPACM_Wlan*)p_iface)->is_guest_ap() )
+		{
+			IPACMDBG_H("Interface %s is guest AP.\n", p_iface->dev_name);
+			m_support_inter_iface_offload = false;
+		}
+	}
+	return;
+}
+
+IPACM_LanToLan_Iface::~IPACM_LanToLan_Iface()
+{
+}
+
+IPACM_LanToLan::IPACM_LanToLan()
+{
+	IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_IFACE_UP, this);
+	IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_IFACE_DOWN, this);
+	IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_CLIENT_ADD, this);
+	IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_CLIENT_DEL, this);
+	IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, this);
+
+	return;
+}
+
+IPACM_LanToLan::~IPACM_LanToLan()
+{
+	IPACMDBG_DMESG("WARNING: UNEXPECTEDLY KILL LAN2LAN CONTROLLER!\n");
+	return;
+}
+
+void IPACM_LanToLan::event_callback(ipa_cm_event_id event, void* param)
+{
+	ipacm_event_eth_bridge *data = (ipacm_event_eth_bridge*)param;
+	IPACMDBG_H("Get %s event.\n", IPACM_Iface::ipacmcfg->getEventName(event));
+
+	switch(event)
+	{
+		case IPA_ETH_BRIDGE_IFACE_UP:
+		{
+			handle_iface_up(data);
+			break;
+		}
+
+		case IPA_ETH_BRIDGE_IFACE_DOWN:
+		{
+			handle_iface_down(data);
+			break;
+		}
+
+		case IPA_ETH_BRIDGE_CLIENT_ADD:
+		{
+			handle_client_add(data);
+			break;
+		}
+
+		case IPA_ETH_BRIDGE_CLIENT_DEL:
+		{
+			handle_client_del(data);
+			break;
+		}
+
+		case IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH:
+		{
+			handle_wlan_scc_mcc_switch(data);
+			break;
+		}
+		default:
+			break;
+	}
+
+	print_data_structure_info();
+	return;
+}
+
+void IPACM_LanToLan::handle_iface_up(ipacm_event_eth_bridge *data)
+{
+	list<IPACM_LanToLan_Iface>::iterator it;
+
+	IPACMDBG_H("Interface name: %s IP type: %d\n", data->p_iface->dev_name, data->iptype);
+	for(it = m_iface.begin(); it != m_iface.end(); it++)
+	{
+		if(it->get_iface_pointer() == data->p_iface)
+		{
+			IPACMDBG_H("Found the interface.\n");
+			if(it->get_m_is_ip_addr_assigned(data->iptype) == false)
+			{
+				IPACMDBG_H("IP type %d was not active before, activating it now.\n", data->iptype);
+				it->set_m_is_ip_addr_assigned(data->iptype, true);
+
+				/* install inter-interface rules */
+				if(it->get_m_support_inter_iface_offload())
+					it->add_all_inter_interface_client_flt_rule(data->iptype);
+
+				/* install intra-BSS rules */
+				if(it->get_m_support_intra_iface_offload())
+					it->add_all_intra_interface_client_flt_rule(data->iptype);
+			}
+			break;
+		}
+	}
+
+	if(it == m_iface.end())	//If the interface has not been created before
+	{
+		if(m_iface.size() == MAX_NUM_IFACE)
+		{
+			IPACMERR("The number of interfaces has reached maximum %d.\n", MAX_NUM_IFACE);
+			return;
+		}
+
+		if(!data->p_iface->tx_prop || !data->p_iface->rx_prop)
+		{
+			IPACMERR("The interface %s does not have tx_prop or rx_prop.\n", data->p_iface->dev_name);
+			return;
+		}
+
+		if(data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_NONE || data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_MAX)
+		{
+			IPACMERR("Invalid l2 header type %s!\n", ipa_l2_hdr_type[data->p_iface->tx_prop->tx[0].hdr_l2_type]);
+			return;
+		}
+
+		IPACMDBG_H("Does not find the interface, insert a new one.\n");
+		IPACM_LanToLan_Iface new_iface(data->p_iface);
+		new_iface.set_m_is_ip_addr_assigned(data->iptype, true);
+
+		m_iface.push_front(new_iface);
+		IPACMDBG_H("Now the total number of interfaces is %d.\n", m_iface.size());
+
+		IPACM_LanToLan_Iface &front_iface = m_iface.front();
+
+		/* install inter-interface rules */
+		if(front_iface.get_m_support_inter_iface_offload())
+		{
+			for(it = ++m_iface.begin(); it != m_iface.end(); it++)
+			{
+				/* add peer info only when both interfaces support inter-interface communication */
+				if(it->get_m_support_inter_iface_offload())
+				{
+					/* populate hdr_proc_ctx and routing table handle */
+					handle_new_iface_up(&front_iface, &(*it));
+
+					/* add client specific routing rule on existing interface */
+					it->add_client_rt_rule_for_new_iface();
+				}
+			}
+
+			/* add client specific filtering rule on new interface */
+			front_iface.add_all_inter_interface_client_flt_rule(data->iptype);
+		}
+
+		/* populate the intra-interface information */
+		if(front_iface.get_m_support_intra_iface_offload())
+		{
+			front_iface.handle_intra_interface_info();
+		}
+
+		/* handle cached client add event */
+		handle_cached_client_add_event(front_iface.get_iface_pointer());
+	}
+	return;
+}
+
+void IPACM_LanToLan::handle_iface_down(ipacm_event_eth_bridge *data)
+{
+	list<IPACM_LanToLan_Iface>::iterator it_target_iface;
+
+	IPACMDBG_H("Interface name: %s\n", data->p_iface->dev_name);
+
+	for(it_target_iface = m_iface.begin(); it_target_iface != m_iface.end(); it_target_iface++)
+	{
+		if(it_target_iface->get_iface_pointer() == data->p_iface)
+		{
+			IPACMDBG_H("Found the interface.\n");
+			break;
+		}
+	}
+
+	if(it_target_iface == m_iface.end())
+	{
+		IPACMDBG_H("The interface has not been found.\n");
+		/* clear cached client add event for the unfound interface*/
+		clear_cached_client_add_event(data->p_iface);
+		return;
+	}
+
+	it_target_iface->handle_down_event();
+	m_iface.erase(it_target_iface);
+
+	return;
+}
+
+void IPACM_LanToLan::handle_new_iface_up(IPACM_LanToLan_Iface *new_iface, IPACM_LanToLan_Iface *exist_iface)
+{
+	char rt_tbl_name_for_flt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+	char rt_tbl_name_for_rt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+
+	IPACMDBG_H("Populate peer info between: new_iface %s, existing iface %s\n", new_iface->get_iface_pointer()->dev_name,
+		exist_iface->get_iface_pointer()->dev_name);
+
+	/* populate the routing table information */
+	snprintf(rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX, "eth_v4_%s_to_%s",
+		ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+		ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+	IPACMDBG_H("IPv4 routing table for flt name: %s\n", rt_tbl_name_for_flt[IPA_IP_v4]);
+
+	snprintf(rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX, "eth_v6_%s_to_%s",
+		ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+		ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+	IPACMDBG_H("IPv6 routing table for flt name: %s\n", rt_tbl_name_for_flt[IPA_IP_v6]);
+
+	snprintf(rt_tbl_name_for_rt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX, "eth_v4_%s_to_%s",
+		ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+		ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+	IPACMDBG_H("IPv4 routing table for rt name: %s\n", rt_tbl_name_for_rt[IPA_IP_v4]);
+
+	snprintf(rt_tbl_name_for_rt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX, "eth_v6_%s_to_%s",
+		ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+		ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+	IPACMDBG_H("IPv6 routing table for rt name: %s\n", rt_tbl_name_for_rt[IPA_IP_v6]);
+
+	/* add new peer info in both new iface and existing iface */
+	exist_iface->handle_new_iface_up(rt_tbl_name_for_flt, rt_tbl_name_for_rt, new_iface);
+
+	new_iface->handle_new_iface_up(rt_tbl_name_for_rt, rt_tbl_name_for_flt, exist_iface);
+
+	return;
+}
+
+void IPACM_LanToLan::handle_client_add(ipacm_event_eth_bridge *data)
+{
+	list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+	IPACMDBG_H("Incoming client MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", data->mac_addr[0], data->mac_addr[1],
+		data->mac_addr[2], data->mac_addr[3], data->mac_addr[4], data->mac_addr[5], data->p_iface->dev_name);
+
+	for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+	{
+		if(it_iface->get_iface_pointer() == data->p_iface)	//find the interface
+		{
+			IPACMDBG_H("Found the interface.\n");
+			it_iface->handle_client_add(data->mac_addr);
+			break;
+		}
+	}
+
+	/* if the iface was not found, cache the client add event */
+	if(it_iface == m_iface.end())
+	{
+		IPACMDBG_H("The interface is not found.\n");
+		if(m_cached_client_add_event.size() < MAX_NUM_CACHED_CLIENT_ADD_EVENT)
+		{
+			IPACMDBG_H("Cached the client information.\n");
+			m_cached_client_add_event.push_front(*data);
+		}
+		else
+		{
+			IPACMDBG_H("Cached client add event has reached maximum number.\n");
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan::handle_client_del(ipacm_event_eth_bridge *data)
+{
+	list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+	IPACMDBG_H("Incoming client MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", data->mac_addr[0], data->mac_addr[1],
+		data->mac_addr[2], data->mac_addr[3], data->mac_addr[4], data->mac_addr[5], data->p_iface->dev_name);
+
+	for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+	{
+		if(it_iface->get_iface_pointer() == data->p_iface)	//found the interface
+		{
+			IPACMDBG_H("Found the interface.\n");
+			it_iface->handle_client_del(data->mac_addr);
+			break;
+		}
+	}
+
+	if(it_iface == m_iface.end())
+	{
+		IPACMDBG_H("The interface is not found.\n");
+	}
+
+	return;
+}
+
+void IPACM_LanToLan::handle_wlan_scc_mcc_switch(ipacm_event_eth_bridge *data)
+{
+	list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+	IPACMDBG_H("Incoming interface: %s\n", data->p_iface->dev_name);
+	for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+	{
+		if(it_iface->get_iface_pointer() == data->p_iface)
+		{
+			it_iface->handle_wlan_scc_mcc_switch();
+			break;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan::handle_cached_client_add_event(IPACM_Lan *p_iface)
+{
+	list<ipacm_event_eth_bridge>::iterator it;
+
+	it = m_cached_client_add_event.begin();
+	while(it != m_cached_client_add_event.end())
+	{
+		if(it->p_iface == p_iface)
+		{
+			IPACMDBG_H("Found client with MAC: 0x%02x%02x%02x%02x%02x%02x\n", it->mac_addr[0], it->mac_addr[1],
+				it->mac_addr[2], it->mac_addr[3], it->mac_addr[4], it->mac_addr[5]);
+			handle_client_add(&(*it));
+			it = m_cached_client_add_event.erase(it);
+		}
+		else
+		{
+			it++;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan::clear_cached_client_add_event(IPACM_Lan *p_iface)
+{
+	list<ipacm_event_eth_bridge>::iterator it;
+
+	it = m_cached_client_add_event.begin();
+	while(it != m_cached_client_add_event.end())
+	{
+		if(it->p_iface == p_iface)
+		{
+			IPACMDBG_H("Found client with MAC: 0x%02x%02x%02x%02x%02x%02x\n", it->mac_addr[0], it->mac_addr[1],
+				it->mac_addr[2], it->mac_addr[3], it->mac_addr[4], it->mac_addr[5]);
+			it = m_cached_client_add_event.erase(it);
+		}
+		else
+		{
+			it++;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan::print_data_structure_info()
+{
+	list<IPACM_LanToLan_Iface>::iterator it;
+	list<ipacm_event_eth_bridge>::iterator it_event;
+	int i;
+
+	IPACMDBG_H("There are %d interfaces in total.\n", m_iface.size());
+
+	for(it = m_iface.begin(); it != m_iface.end(); it++)
+	{
+		it->print_data_structure_info();
+	}
+
+	IPACMDBG_H("There are %d cached client add events in total.\n", m_cached_client_add_event.size());
+
+	i = 1;
+	for(it_event = m_cached_client_add_event.begin(); it_event != m_cached_client_add_event.end(); it_event++)
+	{
+		IPACMDBG_H("Client %d MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", i, it_event->mac_addr[0], it_event->mac_addr[1], it_event->mac_addr[2],
+			it_event->mac_addr[3], it_event->mac_addr[4], it_event->mac_addr[5], it_event->p_iface->dev_name);
+		i++;
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_client_rt_rule_for_new_iface()
+{
+	list<client_info>::iterator it;
+	ipa_hdr_l2_type peer_l2_type;
+	peer_iface_info &peer = m_peer_iface_info.front();
+
+	peer_l2_type = peer.peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 1)
+	{
+		for(it = m_client_info.begin(); it != m_client_info.end(); it++)
+		{
+			add_client_rt_rule(&peer, &(*it));
+		}
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_client_rt_rule(peer_iface_info *peer_info, client_info *client)
+{
+	int i, num_rt_rule;
+	uint32_t rt_rule_hdl[MAX_NUM_PROP];
+	ipa_hdr_l2_type peer_l2_hdr_type;
+
+	peer_l2_hdr_type = peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+
+	/* if the peer info is not for intra interface communication */
+	if(peer_info->peer != this)
+	{
+		IPACMDBG_H("This is for inter interface communication.\n");
+
+		m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v4], hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+			peer_l2_hdr_type, IPA_IP_v4, rt_rule_hdl, &num_rt_rule);
+
+		client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4] = num_rt_rule;
+		IPACMDBG_H("Number of IPv4 routing rule is %d.\n", num_rt_rule);
+		for(i=0; i<num_rt_rule; i++)
+		{
+			IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+			client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i] = rt_rule_hdl[i];
+		}
+
+		m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v6], hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+			peer_l2_hdr_type, IPA_IP_v6, rt_rule_hdl, &num_rt_rule);
+
+		client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6] = num_rt_rule;
+		IPACMDBG_H("Number of IPv6 routing rule is %d.\n", num_rt_rule);
+		for(i=0; i<num_rt_rule; i++)
+		{
+			IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+			client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i] = rt_rule_hdl[i];
+		}
+	}
+	else
+	{
+		IPACMDBG_H("This is for intra interface communication.\n");
+		m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v4], hdr_proc_ctx_for_intra_interface,
+			peer_l2_hdr_type, IPA_IP_v4, rt_rule_hdl, &num_rt_rule);
+
+		client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4] = num_rt_rule;
+		IPACMDBG_H("Number of IPv4 routing rule is %d.\n", num_rt_rule);
+		for(i=0; i<num_rt_rule; i++)
+		{
+			IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+			client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i] = rt_rule_hdl[i];
+		}
+
+		m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v6], hdr_proc_ctx_for_intra_interface,
+			peer_l2_hdr_type, IPA_IP_v6, rt_rule_hdl, &num_rt_rule);
+
+		client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6] = num_rt_rule;
+		IPACMDBG_H("Number of IPv6 routing rule is %d.\n", num_rt_rule);
+		for(i=0; i<num_rt_rule; i++)
+		{
+			IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+			client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i] = rt_rule_hdl[i];
+		}
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_all_inter_interface_client_flt_rule(ipa_ip_type iptype)
+{
+	list<peer_iface_info>::iterator it_iface;
+	list<client_info>::iterator it_client;
+
+	for(it_iface = m_peer_iface_info.begin(); it_iface != m_peer_iface_info.end(); it_iface++)
+	{
+		IPACMDBG_H("Add flt rules for clients of interface %s.\n", it_iface->peer->get_iface_pointer()->dev_name);
+		for(it_client = it_iface->peer->m_client_info.begin(); it_client != it_iface->peer->m_client_info.end(); it_client++)
+		{
+			add_client_flt_rule(&(*it_iface), &(*it_client), iptype);
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_all_intra_interface_client_flt_rule(ipa_ip_type iptype)
+{
+	list<client_info>::iterator it_client;
+
+	IPACMDBG_H("Add flt rules for own clients.\n");
+	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+	{
+		add_client_flt_rule(&m_intra_interface_info, &(*it_client), iptype);
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client)
+{
+	list<peer_iface_info>::iterator it;
+
+	for(it = m_peer_iface_info.begin(); it != m_peer_iface_info.end(); it++)
+	{
+		if(it->peer == peer_iface)
+		{
+			IPACMDBG_H("Found the peer iface info.\n");
+			if(m_is_ip_addr_assigned[IPA_IP_v4])
+			{
+				add_client_flt_rule(&(*it), client, IPA_IP_v4);
+			}
+			if(m_is_ip_addr_assigned[IPA_IP_v6])
+			{
+				add_client_flt_rule(&(*it), client, IPA_IP_v6);
+			}
+
+			break;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_client_flt_rule(peer_iface_info *peer, client_info *client, ipa_ip_type iptype)
+{
+	list<flt_rule_info>::iterator it_flt;
+	uint32_t flt_rule_hdl;
+	flt_rule_info new_flt_info;
+	ipa_ioc_get_rt_tbl rt_tbl;
+
+	rt_tbl.ip = iptype;
+	memcpy(rt_tbl.name, peer->rt_tbl_name_for_flt[iptype], sizeof(rt_tbl.name));
+	IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);
+
+	if(IPACM_Iface::m_routing.GetRoutingTable(&rt_tbl) == false)
+	{
+		IPACMERR("Failed to get routing table.\n");
+		return;
+	}
+
+	m_p_iface->eth_bridge_add_flt_rule(client->mac_addr, rt_tbl.hdl,
+		iptype, &flt_rule_hdl);
+	IPACMDBG_H("Installed flt rule for IP type %d: handle %d\n", iptype, flt_rule_hdl);
+
+	for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
+	{
+		if(it_flt->p_client == client)	//the client is already in the flt info list
+		{
+			IPACMDBG_H("The client is found in flt info list.\n");
+			it_flt->flt_rule_hdl[iptype] = flt_rule_hdl;
+			break;
+		}
+	}
+
+	if(it_flt == peer->flt_rule.end())	//the client is not in the flt info list
+	{
+		IPACMDBG_H("The client is not found in flt info list, insert a new one.\n");
+		memset(&new_flt_info, 0, sizeof(new_flt_info));
+		new_flt_info.p_client = client;
+		new_flt_info.flt_rule_hdl[iptype] = flt_rule_hdl;
+
+		peer->flt_rule.push_front(new_flt_info);
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::del_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client)
+{
+	list<peer_iface_info>::iterator it;
+
+	for(it = m_peer_iface_info.begin(); it != m_peer_iface_info.end(); it++)
+	{
+		if(it->peer == peer_iface)
+		{
+			IPACMDBG_H("Found the peer iface info.\n");
+			del_client_flt_rule(&(*it), client);
+			break;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::del_client_flt_rule(peer_iface_info *peer, client_info *client)
+{
+	list<flt_rule_info>::iterator it_flt;
+
+	for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
+	{
+		if(it_flt->p_client == client)	//found the client in flt info list
+		{
+			IPACMDBG_H("Found the client in flt info list.\n");
+			if(m_is_ip_addr_assigned[IPA_IP_v4])
+			{
+				m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
+				IPACMDBG_H("IPv4 flt rule %d is deleted.\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
+			}
+			if(m_is_ip_addr_assigned[IPA_IP_v6])
+			{
+				m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
+				IPACMDBG_H("IPv6 flt rule %d is deleted.\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
+			}
+
+			peer->flt_rule.erase(it_flt);
+			break;
+		}
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::del_client_rt_rule(peer_iface_info *peer, client_info *client)
+{
+	ipa_hdr_l2_type peer_l2_hdr_type;
+	int i, num_rules;
+
+	peer_l2_hdr_type = peer->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+	/* if the peer info is not for intra interface communication */
+	if(peer->peer != this)
+	{
+		IPACMDBG_H("Delete routing rules for inter interface communication.\n");
+
+		num_rules = client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4];
+		for(i = 0; i < num_rules; i++)
+		{
+			m_p_iface->eth_bridge_del_rt_rule(client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i], IPA_IP_v4);
+			IPACMDBG_H("IPv4 rt rule %d is deleted.\n", client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i]);
+		}
+		client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4] = 0;
+
+		num_rules = client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6];
+		for(i = 0; i < num_rules; i++)
+		{
+			m_p_iface->eth_bridge_del_rt_rule(client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i], IPA_IP_v6);
+			IPACMDBG_H("IPv6 rt rule %d is deleted.\n", client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i]);
+		}
+		client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6] = 0;
+	}
+	else
+	{
+		IPACMDBG_H("Delete routing rules for intra interface communication.\n");
+		num_rules = client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4];
+		for(i = 0; i < num_rules; i++)
+		{
+			m_p_iface->eth_bridge_del_rt_rule(client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i], IPA_IP_v4);
+			IPACMDBG_H("IPv4 rt rule %d is deleted.\n", client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i]);
+		}
+		client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4] = 0;
+
+		num_rules = client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6];
+		for(i = 0; i < num_rules; i++)
+		{
+			m_p_iface->eth_bridge_del_rt_rule(client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i], IPA_IP_v6);
+			IPACMDBG_H("IPv6 rt rule %d is deleted.\n", client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i]);
+		}
+		client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6] = 0;
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_down_event()
+{
+	list<IPACM_LanToLan_Iface>::iterator it_other_iface;
+	list<peer_iface_info>::iterator it_own_peer_info, it_other_iface_peer_info;
+	IPACM_LanToLan_Iface *other_iface;
+
+	/* clear inter-interface rules */
+	if(m_support_inter_iface_offload)
+	{
+		for(it_own_peer_info = m_peer_iface_info.begin(); it_own_peer_info != m_peer_iface_info.end();
+			it_own_peer_info++)
+		{
+			/* decrement reference count of peer l2 header type on both interfaces*/
+			decrement_ref_cnt_peer_l2_hdr_type(it_own_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type);
+			it_own_peer_info->peer->decrement_ref_cnt_peer_l2_hdr_type(m_p_iface->tx_prop->tx[0].hdr_l2_type);
+
+			/* first clear all flt rule on target interface */
+			IPACMDBG_H("Clear all flt rule on target interface.\n");
+			clear_all_flt_rule_for_one_peer_iface(&(*it_own_peer_info));
+
+			other_iface = it_own_peer_info->peer;
+			/* then clear all flt/rt rule and hdr proc ctx for target interface on peer interfaces */
+			IPACMDBG_H("Clear all flt/rt rules and hdr proc ctx for target interface on peer interfaces %s.\n",
+				it_own_peer_info->peer->get_iface_pointer()->dev_name);
+			for(it_other_iface_peer_info = other_iface->m_peer_iface_info.begin();
+				it_other_iface_peer_info != other_iface->m_peer_iface_info.end();
+				it_other_iface_peer_info++)
+			{
+				if(it_other_iface_peer_info->peer == this)	//found myself in other iface's peer info list
+				{
+					IPACMDBG_H("Found the right peer info on other iface.\n");
+					other_iface->clear_all_flt_rule_for_one_peer_iface(&(*it_other_iface_peer_info));
+					other_iface->clear_all_rt_rule_for_one_peer_iface(&(*it_other_iface_peer_info));
+					/* remove the peer info from the list */
+					other_iface->m_peer_iface_info.erase(it_other_iface_peer_info);
+					other_iface->del_hdr_proc_ctx(m_p_iface->tx_prop->tx[0].hdr_l2_type);
+					break;
+				}
+			}
+
+			/* then clear rt rule and hdr proc ctx and release rt table on target interface */
+			IPACMDBG_H("Clear rt rules and hdr proc ctx and release rt table on target interface.\n");
+			clear_all_rt_rule_for_one_peer_iface(&(*it_own_peer_info));
+			del_hdr_proc_ctx(it_own_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type);
+		}
+		m_peer_iface_info.clear();
+	}
+
+	/* clear intra interface rules */
+	if(m_support_intra_iface_offload)
+	{
+		IPACMDBG_H("Clear intra interface flt/rt rules and hdr proc ctx, release rt tables.\n");
+		clear_all_flt_rule_for_one_peer_iface(&m_intra_interface_info);
+		clear_all_rt_rule_for_one_peer_iface(&m_intra_interface_info);
+		m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_intra_interface);
+		IPACMDBG_H("Hdr proc ctx with hdl %d is deleted.\n", hdr_proc_ctx_for_intra_interface);
+	}
+
+	/* then clear the client info list */
+	m_client_info.clear();
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::clear_all_flt_rule_for_one_peer_iface(peer_iface_info *peer)
+{
+	list<flt_rule_info>::iterator it;
+
+	for(it = peer->flt_rule.begin(); it != peer->flt_rule.end(); it++)
+	{
+		if(m_is_ip_addr_assigned[IPA_IP_v4])
+		{
+			m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
+			IPACMDBG_H("IPv4 flt rule %d is deleted.\n", it->flt_rule_hdl[IPA_IP_v4]);
+		}
+		if(m_is_ip_addr_assigned[IPA_IP_v6])
+		{
+			m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
+			IPACMDBG_H("IPv6 flt rule %d is deleted.\n", it->flt_rule_hdl[IPA_IP_v6]);
+		}
+	}
+	peer->flt_rule.clear();
+	return;
+}
+
+void IPACM_LanToLan_Iface::clear_all_rt_rule_for_one_peer_iface(peer_iface_info *peer)
+{
+	list<client_info>::iterator it;
+	ipa_hdr_l2_type peer_l2_type;
+
+	peer_l2_type = peer->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 0)
+	{
+		for(it = m_client_info.begin(); it != m_client_info.end(); it++)
+		{
+			del_client_rt_rule(peer, &(*it));
+		}
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_wlan_scc_mcc_switch()
+{
+	list<peer_iface_info>::iterator it_peer_info;
+	list<client_info>::iterator it_client;
+	ipa_hdr_l2_type peer_l2_hdr_type;
+	bool flag[IPA_HDR_L2_MAX];
+	int i;
+
+	/* modify inter-interface routing rules */
+	if(m_support_inter_iface_offload)
+	{
+		IPACMDBG_H("Modify rt rules for peer interfaces.\n");
+		memset(flag, 0, sizeof(flag));
+		for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+		{
+			peer_l2_hdr_type = it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+			if(flag[peer_l2_hdr_type] == false)
+			{
+				flag[peer_l2_hdr_type] = true;
+				for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+				{
+					m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+						peer_l2_hdr_type, IPA_IP_v4, it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4],
+						it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4]);
+					IPACMDBG_H("The following IPv4 routing rules are modified:\n");
+					for(i = 0; i < it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4]; i++)
+					{
+						IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i]);
+					}
+
+					m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+						peer_l2_hdr_type, IPA_IP_v6, it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6],
+						it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6]);
+					IPACMDBG_H("The following IPv6 routing rules are modified:\n");
+					for(i = 0; i < it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6]; i++)
+					{
+						IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i]);
+					}
+				}
+			}
+		}
+	}
+
+	/* modify routing rules for intra-interface communication */
+	IPACMDBG_H("Modify rt rules for intra-interface communication.\n");
+	if(m_support_intra_iface_offload)
+	{
+		for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+		{
+			m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_intra_interface,
+				m_p_iface->tx_prop->tx[0].hdr_l2_type, IPA_IP_v4, it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4],
+				it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]);
+			IPACMDBG_H("The following IPv4 routing rules are modified:\n");
+			for(i = 0; i < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]; i++)
+			{
+				IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i]);
+			}
+
+			m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_intra_interface,
+				m_p_iface->tx_prop->tx[0].hdr_l2_type, IPA_IP_v6, it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6],
+				it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]);
+			IPACMDBG_H("The following IPv6 routing rules are modified:\n");
+			for(i = 0; i < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]; i++)
+			{
+				IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i]);
+			}
+		}
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_intra_interface_info()
+{
+	uint32_t hdr_proc_ctx_hdl;
+
+	if(m_p_iface->tx_prop == NULL)
+	{
+		IPACMERR("No tx prop.\n");
+		return;
+	}
+
+	m_intra_interface_info.peer = this;
+
+	snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX,
+		"eth_v4_intra_interface");
+	IPACMDBG_H("IPv4 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4]);
+	snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX,
+		"eth_v6_intra_interface");
+	IPACMDBG_H("IPv6 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6]);
+
+	memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4],
+		IPA_RESOURCE_NAME_MAX);
+	IPACMDBG_H("IPv4 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4]);
+	memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6],
+		IPA_RESOURCE_NAME_MAX);
+	IPACMDBG_H("IPv6 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6]);
+
+	m_p_iface->eth_bridge_add_hdr_proc_ctx(m_p_iface->tx_prop->tx[0].hdr_l2_type,
+		&hdr_proc_ctx_hdl);
+	hdr_proc_ctx_for_intra_interface = hdr_proc_ctx_hdl;
+	IPACMDBG_H("Hdr proc ctx for intra-interface communication: hdl %d\n", hdr_proc_ctx_hdl);
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_new_iface_up(char rt_tbl_name_for_flt[][IPA_RESOURCE_NAME_MAX], char rt_tbl_name_for_rt[][IPA_RESOURCE_NAME_MAX],
+		IPACM_LanToLan_Iface *peer_iface)
+{
+	peer_iface_info new_peer;
+	ipa_hdr_l2_type peer_l2_hdr_type;
+
+	new_peer.peer = peer_iface;
+	memcpy(new_peer.rt_tbl_name_for_rt[IPA_IP_v4], rt_tbl_name_for_rt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX);
+	memcpy(new_peer.rt_tbl_name_for_rt[IPA_IP_v6], rt_tbl_name_for_rt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX);
+	memcpy(new_peer.rt_tbl_name_for_flt[IPA_IP_v4], rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX);
+	memcpy(new_peer.rt_tbl_name_for_flt[IPA_IP_v6], rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX);
+
+	peer_l2_hdr_type = peer_iface->m_p_iface->tx_prop->tx[0].hdr_l2_type;
+	increment_ref_cnt_peer_l2_hdr_type(peer_l2_hdr_type);
+	add_hdr_proc_ctx(peer_l2_hdr_type);
+
+	/* push the new peer_iface_info into the list */
+	m_peer_iface_info.push_front(new_peer);
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_client_add(uint8_t *mac)
+{
+	list<client_info>::iterator it_client;
+	list<peer_iface_info>::iterator it_peer_info;
+	client_info new_client;
+	bool flag[IPA_HDR_L2_MAX];
+
+	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+	{
+		if(memcmp(it_client->mac_addr, mac, sizeof(it_client->mac_addr)) == 0)
+		{
+			IPACMDBG_H("This client has been added before.\n");
+			return;
+		}
+	}
+
+	if(m_client_info.size() == MAX_NUM_CLIENT)
+	{
+		IPACMDBG_H("The number of clients has reached maximum %d.\n", MAX_NUM_CLIENT);
+		return;
+	}
+
+	memcpy(new_client.mac_addr, mac, sizeof(new_client.mac_addr));
+	m_client_info.push_front(new_client);
+
+	client_info &front_client = m_client_info.front();
+
+	/* install inter-interface rules */
+	if(m_support_inter_iface_offload)
+	{
+		memset(flag, 0, sizeof(flag));
+		for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+		{
+			/* make sure add routing rule only once for each peer l2 header type */
+			if(flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] == false)
+			{
+				/* add client routing rule for each peer interface */
+				add_client_rt_rule(&(*it_peer_info), &front_client);
+				flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] = true;
+			}
+
+			/* add client filtering rule on peer interfaces */
+			it_peer_info->peer->add_one_client_flt_rule(this, &front_client);
+		}
+	}
+
+	/* install intra-interface rules */
+	if(m_support_intra_iface_offload)
+	{
+		/* add routing rule first */
+		add_client_rt_rule(&m_intra_interface_info, &front_client);
+
+		/* add filtering rule */
+		if(m_is_ip_addr_assigned[IPA_IP_v4])
+		{
+			add_client_flt_rule(&m_intra_interface_info, &front_client, IPA_IP_v4);
+		}
+		if(m_is_ip_addr_assigned[IPA_IP_v6])
+		{
+			add_client_flt_rule(&m_intra_interface_info, &front_client, IPA_IP_v6);
+		}
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::handle_client_del(uint8_t *mac)
+{
+	list<client_info>::iterator it_client;
+	list<peer_iface_info>::iterator it_peer_info;
+	bool flag[IPA_HDR_L2_MAX];
+
+	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+	{
+		if(memcmp(it_client->mac_addr, mac, sizeof(it_client->mac_addr)) == 0)	//found the client
+		{
+			IPACMDBG_H("Found the client.\n");
+			break;
+		}
+	}
+
+	if(it_client != m_client_info.end())	//if we found the client
+	{
+		/* uninstall inter-interface rules */
+		if(m_support_inter_iface_offload)
+		{
+			memset(flag, 0, sizeof(flag));
+			for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end();
+				it_peer_info++)
+			{
+				IPACMDBG_H("Delete client filtering rule on peer interface.\n");
+				it_peer_info->peer->del_one_client_flt_rule(this, &(*it_client));
+
+				/* make sure to delete routing rule only once for each peer l2 header type */
+				if(flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] == false)
+				{
+					IPACMDBG_H("Delete client routing rule for peer interface.\n");
+					del_client_rt_rule(&(*it_peer_info), &(*it_client));
+					flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] = true;
+				}
+			}
+		}
+
+		/* uninstall intra-interface rules */
+		if(m_support_intra_iface_offload)
+		{
+			/* delete filtering rule first */
+			IPACMDBG_H("Delete client filtering rule for intra-interface communication.\n");
+			del_client_flt_rule(&m_intra_interface_info, &(*it_client));
+
+			/* delete routing rule */
+			IPACMDBG_H("Delete client routing rule for intra-interface communication.\n");
+			del_client_rt_rule(&m_intra_interface_info, &(*it_client));
+		}
+
+		/* erase the client from client info list */
+		m_client_info.erase(it_client);
+	}
+	else
+	{
+		IPACMDBG_H("The client is not found.\n");
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
+{
+	uint32_t hdr_proc_ctx_hdl;
+
+	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 1)
+	{
+		m_p_iface->eth_bridge_add_hdr_proc_ctx(peer_l2_type, &hdr_proc_ctx_hdl);
+		hdr_proc_ctx_for_inter_interface[peer_l2_type] = hdr_proc_ctx_hdl;
+		IPACMDBG_H("Installed inter-interface hdr proc ctx on iface %s: handle %d\n", m_p_iface->dev_name, hdr_proc_ctx_hdl);
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::del_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
+{
+	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 0)
+	{
+		m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_inter_interface[peer_l2_type]);
+		IPACMDBG_H("Hdr proc ctx with hdl %d is deleted.\n", hdr_proc_ctx_for_inter_interface[peer_l2_type]);
+	}
+	return;
+}
+
+void IPACM_LanToLan_Iface::print_data_structure_info()
+{
+	list<peer_iface_info>::iterator it_peer;
+	list<client_info>::iterator it_client;
+	int i, j, k;
+
+	IPACMDBG_H("\n");
+	IPACMDBG_H("Interface %s:\n", m_p_iface->dev_name);
+	IPACMDBG_H("Is IPv4 addr assigned? %d\n", m_is_ip_addr_assigned[IPA_IP_v4]);
+	IPACMDBG_H("Is IPv6 addr assigned? %d\n", m_is_ip_addr_assigned[IPA_IP_v6]);
+	IPACMDBG_H("Support inter interface offload? %d\n", m_support_inter_iface_offload);
+	IPACMDBG_H("Support intra interface offload? %d\n", m_support_intra_iface_offload);
+
+	if(m_support_inter_iface_offload)
+	{
+		for(i = 0; i < IPA_HDR_L2_MAX; i++)
+		{
+			IPACMDBG_H("Ref_cnt of peer l2 type %s is %d.\n", ipa_l2_hdr_type[i], ref_cnt_peer_l2_hdr_type[i]);
+			if(ref_cnt_peer_l2_hdr_type[i] > 0)
+			{
+				IPACMDBG_H("Hdr proc ctx for peer l2 type %s: %d\n", ipa_l2_hdr_type[i], hdr_proc_ctx_for_inter_interface[i]);
+			}
+		}
+	}
+
+	if(m_support_intra_iface_offload)
+	{
+		IPACMDBG_H("Hdr proc ctx for intra-interface: %d\n", hdr_proc_ctx_for_intra_interface);
+	}
+
+	i = 1;
+	IPACMDBG_H("There are %d clients in total.\n", m_client_info.size());
+	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+	{
+		IPACMDBG_H("Client %d MAC: 0x%02x%02x%02x%02x%02x%02x Pointer: 0x%08x\n", i, it_client->mac_addr[0], it_client->mac_addr[1],
+			it_client->mac_addr[2], it_client->mac_addr[3], it_client->mac_addr[4], it_client->mac_addr[5], &(*it_client));
+
+		if(m_support_inter_iface_offload)
+		{
+			for(j = 0; j < IPA_HDR_L2_MAX; j++)
+			{
+				if(ref_cnt_peer_l2_hdr_type[j] > 0)
+				{
+					IPACMDBG_H("Printing routing rule info for inter-interface communication for peer l2 type %s.\n",
+						ipa_l2_hdr_type[j]);
+					IPACMDBG_H("Number of IPv4 routing rules is %d, handles:\n", it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v4]);
+					for(k = 0; k < it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v4]; k++)
+					{
+						IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[j].rule_hdl[IPA_IP_v4][k]);
+					}
+
+					IPACMDBG_H("Number of IPv6 routing rules is %d, handles:\n", it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v6]);
+					for(k = 0; k < it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v6]; k++)
+					{
+						IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[j].rule_hdl[IPA_IP_v6][k]);
+					}
+				}
+			}
+		}
+
+		if(m_support_intra_iface_offload)
+		{
+			IPACMDBG_H("Printing routing rule info for intra-interface communication.\n");
+			IPACMDBG_H("Number of IPv4 routing rules is %d, handles:\n", it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]);
+			for(j = 0; j < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]; j++)
+			{
+				IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][j]);
+			}
+
+			IPACMDBG_H("Number of IPv6 routing rules is %d, handles:\n", it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]);
+			for(j = 0; j < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]; j++)
+			{
+				IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][j]);
+			}
+		}
+		i++;
+	}
+
+	IPACMDBG_H("There are %d peer interfaces in total.\n", m_peer_iface_info.size());
+	for(it_peer = m_peer_iface_info.begin(); it_peer != m_peer_iface_info.end(); it_peer++)
+	{
+		print_peer_info(&(*it_peer));
+	}
+
+	if(m_support_intra_iface_offload)
+	{
+		IPACMDBG_H("This interface supports intra-interface communication, printing info:\n");
+		print_peer_info(&m_intra_interface_info);
+	}
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::print_peer_info(peer_iface_info *peer_info)
+{
+	list<flt_rule_info>::iterator it_flt;
+	list<rt_rule_info>::iterator it_rt;
+
+	IPACMDBG_H("Printing peer info for iface %s:\n", peer_info->peer->m_p_iface->dev_name);
+
+	IPACMDBG_H("There are %d flt info in total.\n", peer_info->flt_rule.size());
+	for(it_flt = peer_info->flt_rule.begin(); it_flt != peer_info->flt_rule.end(); it_flt++)
+	{
+		IPACMDBG_H("Flt rule handle for client 0x%08x:\n", it_flt->p_client);
+		if(m_is_ip_addr_assigned[IPA_IP_v4])
+		{
+			IPACMDBG_H("IPv4 %d\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
+		}
+		if(m_is_ip_addr_assigned[IPA_IP_v6])
+		{
+			IPACMDBG_H("IPv6 %d\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
+		}
+	}
+
+	return;
+}
+
+IPACM_Lan* IPACM_LanToLan_Iface::get_iface_pointer()
+{
+	return m_p_iface;
+}
+
+bool IPACM_LanToLan_Iface::get_m_is_ip_addr_assigned(ipa_ip_type iptype)
+{
+	IPACMDBG_H("Has IP address been assigned to interface %s for IP type %d? %d\n",
+		m_p_iface->dev_name, iptype, m_is_ip_addr_assigned[iptype]);
+	return m_is_ip_addr_assigned[iptype];
+}
+
+void IPACM_LanToLan_Iface::set_m_is_ip_addr_assigned(ipa_ip_type iptype, bool value)
+{
+	IPACMDBG_H("Is IP address of IP type %d assigned to interface %s? %d\n", iptype,
+		m_p_iface->dev_name, value);
+	m_is_ip_addr_assigned[iptype] = value;
+}
+
+bool IPACM_LanToLan_Iface::get_m_support_inter_iface_offload()
+{
+	IPACMDBG_H("Support inter interface offload on %s? %d\n", m_p_iface->dev_name,
+		m_support_inter_iface_offload);
+	return m_support_inter_iface_offload;
+}
+
+bool IPACM_LanToLan_Iface::get_m_support_intra_iface_offload()
+{
+	IPACMDBG_H("Support intra interface offload on %s? %d\n", m_p_iface->dev_name,
+		m_support_intra_iface_offload);
+	return m_support_intra_iface_offload;
+}
+
+void IPACM_LanToLan_Iface::increment_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type)
+{
+	ref_cnt_peer_l2_hdr_type[peer_l2_type]++;
+	IPACMDBG_H("Now the ref_cnt of peer l2 hdr type %s is %d.\n", ipa_l2_hdr_type[peer_l2_type],
+		ref_cnt_peer_l2_hdr_type[peer_l2_type]);
+
+	return;
+}
+
+void IPACM_LanToLan_Iface::decrement_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type)
+{
+	ref_cnt_peer_l2_hdr_type[peer_l2_type]--;
+	IPACMDBG_H("Now the ref_cnt of peer l2 hdr type %s is %d.\n", ipa_l2_hdr_type[peer_l2_type],
+		ref_cnt_peer_l2_hdr_type[peer_l2_type]);
+
+	return;
+}
diff --git a/ipacm/src/IPACM_Log.cpp b/ipacm/src/IPACM_Log.cpp
new file mode 100644
index 0000000..20dd26c
--- /dev/null
+++ b/ipacm/src/IPACM_Log.cpp
@@ -0,0 +1,107 @@
+/* 
+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 "IPACM_Log.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <asm/types.h>
+#include <linux/if.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <IPACM_Defs.h>
+
+void logmessage(int log_level)
+{
+	return;
+}
+
+/* start IPACMDIAG socket*/
+int create_socket(unsigned int *sockfd)
+{
+
+  if ((*sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) == IPACM_FAILURE)
+  {
+    perror("Error creating ipacm_log socket\n");
+    return IPACM_FAILURE;
+  }
+
+  if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0)
+  {
+    perror("Couldn't set ipacm_log Close on Exec\n");
+  }
+
+  return IPACM_SUCCESS;
+}
+
+void ipacm_log_send( void * user_data)
+{
+	ipacm_log_buffer_t ipacm_log_buffer;
+	int numBytes=0, len;
+	struct sockaddr_un ipacmlog_socket;
+	static unsigned int ipacm_log_sockfd = 0;
+
+	if(ipacm_log_sockfd == 0)
+	{
+		/* start ipacm_log socket */
+		if(create_socket(&ipacm_log_sockfd) < 0)
+		{
+			printf("unable to create ipacm_log socket\n");
+			return;
+		}
+		printf("create ipacm_log socket successfully\n");
+	}
+	ipacmlog_socket.sun_family = AF_UNIX;
+	strcpy(ipacmlog_socket.sun_path, IPACMLOG_FILE);
+	len = strlen(ipacmlog_socket.sun_path) + sizeof(ipacmlog_socket.sun_family);
+
+	memcpy(ipacm_log_buffer.user_data, user_data, MAX_BUF_LEN);
+
+	//printf("send : %s\n", ipacm_log_buffer.user_data);
+	if ((numBytes = sendto(ipacm_log_sockfd, (void *)&ipacm_log_buffer, sizeof(ipacm_log_buffer.user_data), 0,
+			(struct sockaddr *)&ipacmlog_socket, len)) == -1)
+	{
+		printf("Send Failed(%d) %s \n",errno,strerror(errno));
+		return;
+	}
+	return;
+}
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
new file mode 100644
index 0000000..c6ab9ee
--- /dev/null
+++ b/ipacm/src/IPACM_Main.cpp
@@ -0,0 +1,939 @@
+/*
+Copyright (c) 2013-2016, 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_Main.cpp
+
+	@brief
+	This file implements the IPAM functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+/******************************************************************************
+
+                      IPCM_MAIN.C
+
+******************************************************************************/
+
+#include <sys/socket.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "linux/ipa_qmi_service_v01.h"
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Neighbor.h"
+#include "IPACM_IfaceManager.h"
+#include "IPACM_Log.h"
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Netlink.h"
+
+/* not defined(FEATURE_IPA_ANDROID)*/
+#ifndef FEATURE_IPA_ANDROID
+#include "IPACM_LanToLan.h"
+#endif
+
+#define IPA_DRIVER  "/dev/ipa"
+
+#define IPACM_FIREWALL_FILE_NAME    "mobileap_firewall.xml"
+#define IPACM_CFG_FILE_NAME    "IPACM_cfg.xml"
+#ifdef FEATURE_IPA_ANDROID
+#define IPACM_PID_FILE "/data/misc/ipa/ipacm.pid"
+#define IPACM_DIR_NAME     "/data"
+#else/* defined(FEATURE_IPA_ANDROID) */
+#define IPACM_PID_FILE "/etc/ipacm.pid"
+#define IPACM_DIR_NAME     "/etc"
+#endif /* defined(NOT FEATURE_IPA_ANDROID)*/
+#define IPACM_NAME "ipacm"
+
+#define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN     (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FIREWALL_FILE_NAME))
+
+#define IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS  3
+#define IPA_DRIVER_WLAN_EVENT_SIZE  (sizeof(struct ipa_wlan_msg_ex)+ IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS*sizeof(ipa_wlan_hdr_attrib_val))
+#define IPA_DRIVER_PIPE_STATS_EVENT_SIZE  (sizeof(struct ipa_get_data_stats_resp_msg_v01))
+#define IPA_DRIVER_WLAN_META_MSG    (sizeof(struct ipa_msg_meta))
+#define IPA_DRIVER_WLAN_BUF_LEN     (IPA_DRIVER_PIPE_STATS_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
+
+uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
+bool ipacm_logging = true;
+
+void ipa_is_ipacm_running(void);
+int ipa_get_if_index(char *if_name, int *if_index);
+
+/* start netlink socket monitor*/
+void* netlink_start(void *param)
+{
+	ipa_nl_sk_fd_set_info_t sk_fdset;
+	int ret_val = 0;
+	memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
+	IPACMDBG_H("netlink starter memset sk_fdset succeeds\n");
+	ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
+																										RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
+																										RTNLGRP_IPV6_PREFIX),
+																 &sk_fdset, ipa_nl_recv_msg);
+
+	if (ret_val != IPACM_SUCCESS)
+	{
+		IPACMERR("Failed to initialize IPA netlink event listener\n");
+		return NULL;
+	}
+
+	return NULL;
+}
+
+/* start firewall-rule monitor*/
+void* firewall_monitor(void *param)
+{
+	int length;
+	int wd;
+	char buffer[INOTIFY_BUF_LEN];
+	int inotify_fd;
+	ipacm_cmd_q_data evt_data;
+	uint32_t mask = IN_MODIFY | IN_MOVE;
+
+	inotify_fd = inotify_init();
+	if (inotify_fd < 0)
+	{
+		PERROR("inotify_init");
+	}
+
+	IPACMDBG_H("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
+
+	wd = inotify_add_watch(inotify_fd,
+												 IPACM_DIR_NAME,
+												 mask);
+
+	while (1)
+	{
+		length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
+		if (length < 0)
+		{
+			IPACMERR("inotify read() error return length: %d and mask: 0x%x\n", length, mask);
+			continue;
+		}
+
+		struct inotify_event* event;
+		event = (struct inotify_event*)malloc(length);
+		if(event == NULL)
+		{
+			IPACMERR("Failed to allocate memory.\n");
+			return NULL;
+		}
+		memset(event, 0, length);
+		memcpy(event, buffer, length);
+
+		if (event->len > 0)
+		{
+			if ( (event->mask & IN_MODIFY) || (event->mask & IN_MOVE))
+			{
+				if (event->mask & IN_ISDIR)
+				{
+					IPACMDBG_H("The directory %s was 0x%x\n", event->name, event->mask);
+				}
+				else if (!strncmp(event->name, IPACM_FIREWALL_FILE_NAME, event->len)) // firewall_rule change
+				{
+					IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
+					IPACMDBG_H("The interested file %s .\n", IPACM_FIREWALL_FILE_NAME);
+
+					evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
+					evt_data.evt_data = NULL;
+
+					/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+				}
+				else if (!strncmp(event->name, IPACM_CFG_FILE_NAME, event->len)) // IPACM_configuration change
+				{
+					IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
+					IPACMDBG_H("The interested file %s .\n", IPACM_CFG_FILE_NAME);
+
+					evt_data.event = IPA_CFG_CHANGE_EVENT;
+					evt_data.evt_data = NULL;
+
+					/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+				}
+			}
+			IPACMDBG_H("Received monitoring event %s.\n", event->name);
+		}
+		free(event);
+	}
+
+	(void)inotify_rm_watch(inotify_fd, wd);
+	(void)close(inotify_fd);
+	return NULL;
+}
+
+
+/* start IPACM wan-driver notifier */
+void* ipa_driver_msg_notifier(void *param)
+{
+	int length, fd, cnt;
+	char buffer[IPA_DRIVER_WLAN_BUF_LEN];
+	struct ipa_msg_meta event_hdr;
+	struct ipa_ecm_msg event_ecm;
+	struct ipa_wan_msg event_wan;
+	struct ipa_wlan_msg_ex event_ex_o;
+	struct ipa_wlan_msg *event_wlan=NULL;
+	struct ipa_wlan_msg_ex *event_ex= NULL;
+	struct ipa_get_data_stats_resp_msg_v01 event_data_stats;
+	struct ipa_get_apn_data_stats_resp_msg_v01 event_network_stats;
+
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_data_mac *data = NULL;
+	ipacm_event_data_fid *data_fid = NULL;
+	ipacm_event_data_iptype *data_iptype = NULL;
+	ipacm_event_data_wlan_ex *data_ex;
+	ipa_get_data_stats_resp_msg_v01 *data_tethering_stats = NULL;
+	ipa_get_apn_data_stats_resp_msg_v01 *data_network_stats = NULL;
+
+	ipacm_cmd_q_data new_neigh_evt;
+	ipacm_event_data_all* new_neigh_data;
+
+	fd = open(IPA_DRIVER, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DRIVER);
+		return NULL;
+	}
+
+	while (1)
+	{
+		IPACMDBG_H("Waiting for nofications from IPA driver \n");
+		memset(buffer, 0, sizeof(buffer));
+		memset(&evt_data, 0, sizeof(evt_data));
+		memset(&new_neigh_evt, 0, sizeof(ipacm_cmd_q_data));
+		new_neigh_data = NULL;
+		data = NULL;
+		data_fid = NULL;
+		data_tethering_stats = NULL;
+		data_network_stats = NULL;
+
+		length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
+		if (length < 0)
+		{
+			PERROR("didn't read IPA_driver correctly");
+			continue;
+		}
+
+		memcpy(&event_hdr, buffer,sizeof(struct ipa_msg_meta));
+		IPACMDBG_H("Message type: %d\n", event_hdr.msg_type);
+		IPACMDBG_H("Event header length received: %d\n",event_hdr.msg_len);
+
+		/* Insert WLAN_DRIVER_EVENT to command queue */
+		switch (event_hdr.msg_type)
+		{
+
+		case SW_ROUTING_ENABLE:
+			IPACMDBG_H("Received SW_ROUTING_ENABLE\n");
+			evt_data.event = IPA_SW_ROUTING_ENABLE;
+			IPACMDBG_H("Not supported anymore\n");
+			continue;
+
+		case SW_ROUTING_DISABLE:
+			IPACMDBG_H("Received SW_ROUTING_DISABLE\n");
+			evt_data.event = IPA_SW_ROUTING_DISABLE;
+			IPACMDBG_H("Not supported anymore\n");
+			continue;
+
+		case WLAN_AP_CONNECT:
+			event_wlan = (struct ipa_wlan_msg *) (buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Received WLAN_AP_CONNECT name: %s\n",event_wlan->name);
+			IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+                        data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+			evt_data.event = IPA_WLAN_AP_LINK_UP_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+
+		case WLAN_AP_DISCONNECT:
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Received WLAN_AP_DISCONNECT name: %s\n",event_wlan->name);
+			IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+                        data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+			evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+		case WLAN_STA_CONNECT:
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Received WLAN_STA_CONNECT name: %s\n",event_wlan->name);
+			IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+			data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+			if(data == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+				return NULL;
+			}
+			memcpy(data->mac_addr,
+				 event_wlan->mac_addr,
+				 sizeof(event_wlan->mac_addr));
+			ipa_get_if_index(event_wlan->name, &(data->if_index));
+			evt_data.event = IPA_WLAN_STA_LINK_UP_EVENT;
+			evt_data.evt_data = data;
+			break;
+
+		case WLAN_STA_DISCONNECT:
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Received WLAN_STA_DISCONNECT name: %s\n",event_wlan->name);
+			IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+                        data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+			evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+
+		case WLAN_CLIENT_CONNECT:
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Received WLAN_CLIENT_CONNECT\n");
+			IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+		        data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+		        if (data == NULL)
+		        {
+		    	        IPACMERR("unable to allocate memory for event_wlan data\n");
+		    	        return NULL;
+		        }
+			memcpy(data->mac_addr,
+						 event_wlan->mac_addr,
+						 sizeof(event_wlan->mac_addr));
+			ipa_get_if_index(event_wlan->name, &(data->if_index));
+		        evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
+			evt_data.evt_data = data;
+			break;
+
+		case WLAN_CLIENT_CONNECT_EX:
+			IPACMDBG_H("Received WLAN_CLIENT_CONNECT_EX\n");
+
+			memcpy(&event_ex_o, buffer + sizeof(struct ipa_msg_meta),sizeof(struct ipa_wlan_msg_ex));
+			if(event_ex_o.num_of_attribs > IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS)
+			{
+				IPACMERR("buffer size overflow\n");
+				return NULL;
+			}
+			length = sizeof(ipa_wlan_msg_ex)+ event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val);
+			IPACMDBG_H("num_of_attribs %d, length %d\n", event_ex_o.num_of_attribs, length);
+			event_ex = (ipa_wlan_msg_ex *)malloc(length);
+			if(event_ex == NULL )
+			{
+				IPACMERR("Unable to allocate memory\n");
+				return NULL;
+			}
+			memcpy(event_ex, buffer + sizeof(struct ipa_msg_meta), length);
+			data_ex = (ipacm_event_data_wlan_ex *)malloc(sizeof(ipacm_event_data_wlan_ex) + event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
+		    if (data_ex == NULL)
+		    {
+				IPACMERR("unable to allocate memory for event data\n");
+		    	return NULL;
+		    }
+			data_ex->num_of_attribs = event_ex->num_of_attribs;
+
+			memcpy(data_ex->attribs,
+						event_ex->attribs,
+						event_ex->num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
+
+			ipa_get_if_index(event_ex->name, &(data_ex->if_index));
+			evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT_EX;
+			evt_data.evt_data = data_ex;
+
+			/* Construct new_neighbor msg with netdev device internally */
+			new_neigh_data = (ipacm_event_data_all*)malloc(sizeof(ipacm_event_data_all));
+			if(new_neigh_data == NULL)
+			{
+				IPACMERR("Failed to allocate memory.\n");
+				return NULL;
+			}
+			memset(new_neigh_data, 0, sizeof(ipacm_event_data_all));
+			new_neigh_data->iptype = IPA_IP_v6;
+			for(cnt = 0; cnt < event_ex->num_of_attribs; cnt++)
+			{
+				if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+				{
+					memcpy(new_neigh_data->mac_addr, event_ex->attribs[cnt].u.mac_addr, sizeof(new_neigh_data->mac_addr));
+					IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+								 event_ex->attribs[cnt].u.mac_addr[0], event_ex->attribs[cnt].u.mac_addr[1], event_ex->attribs[cnt].u.mac_addr[2],
+								 event_ex->attribs[cnt].u.mac_addr[3], event_ex->attribs[cnt].u.mac_addr[4], event_ex->attribs[cnt].u.mac_addr[5]);
+				}
+				else if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+				{
+					IPACMDBG_H("Wlan client id %d\n",event_ex->attribs[cnt].u.sta_id);
+				}
+				else
+				{
+					IPACMDBG_H("Wlan message has unexpected type!\n");
+				}
+			}
+			new_neigh_data->if_index = data_ex->if_index;
+			new_neigh_evt.evt_data = (void*)new_neigh_data;
+			new_neigh_evt.event = IPA_NEW_NEIGH_EVENT;
+			free(event_ex);
+			break;
+
+		case WLAN_CLIENT_DISCONNECT:
+			IPACMDBG_H("Received WLAN_CLIENT_DISCONNECT\n");
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+		        data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+		        if (data == NULL)
+		        {
+		    	        IPACMERR("unable to allocate memory for event_wlan data\n");
+		    	        return NULL;
+		        }
+			memcpy(data->mac_addr,
+						 event_wlan->mac_addr,
+						 sizeof(event_wlan->mac_addr));
+			ipa_get_if_index(event_wlan->name, &(data->if_index));
+			evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
+			evt_data.evt_data = data;
+			break;
+
+		case WLAN_CLIENT_POWER_SAVE_MODE:
+			IPACMDBG_H("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+		        data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+		        if (data == NULL)
+		        {
+		    	        IPACMERR("unable to allocate memory for event_wlan data\n");
+		    	        return NULL;
+		        }
+			memcpy(data->mac_addr,
+						 event_wlan->mac_addr,
+						 sizeof(event_wlan->mac_addr));
+			ipa_get_if_index(event_wlan->name, &(data->if_index));
+			evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
+			evt_data.evt_data = data;
+			break;
+
+		case WLAN_CLIENT_NORMAL_MODE:
+			IPACMDBG_H("Received WLAN_CLIENT_NORMAL_MODE\n");
+			event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+			IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+							 event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+		        data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+		        if (data == NULL)
+		        {
+		    	       IPACMERR("unable to allocate memory for event_wlan data\n");
+		    	       return NULL;
+		        }
+			memcpy(data->mac_addr,
+						 event_wlan->mac_addr,
+						 sizeof(event_wlan->mac_addr));
+			ipa_get_if_index(event_wlan->name, &(data->if_index));
+			evt_data.evt_data = data;
+			evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
+			break;
+
+		case ECM_CONNECT:
+			memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
+			IPACMDBG_H("Received ECM_CONNECT name: %s\n",event_ecm.name);
+			data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_ecm data_fid\n");
+				return NULL;
+			}
+			data_fid->if_index = event_ecm.ifindex;
+			evt_data.event = IPA_USB_LINK_UP_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+
+		case ECM_DISCONNECT:
+			memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
+			IPACMDBG_H("Received ECM_DISCONNECT name: %s\n",event_ecm.name);
+			data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_ecm data_fid\n");
+				return NULL;
+			}
+			data_fid->if_index = event_ecm.ifindex;
+			evt_data.event = IPA_LINK_DOWN_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+		/* Add for 8994 Android case */
+		case WAN_UPSTREAM_ROUTE_ADD:
+			memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+			IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
+			data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
+			if(data_iptype == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
+			ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
+			data_iptype->iptype = event_wan.ip;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+			data_iptype->ipv4_addr_gw = event_wan.ipv4_addr_gw;
+			data_iptype->ipv6_addr_gw[0] = event_wan.ipv6_addr_gw[0];
+			data_iptype->ipv6_addr_gw[1] = event_wan.ipv6_addr_gw[1];
+			data_iptype->ipv6_addr_gw[2] = event_wan.ipv6_addr_gw[2];
+			data_iptype->ipv6_addr_gw[3] = event_wan.ipv6_addr_gw[3];
+			IPACMDBG_H("default gw ipv4 (%x)\n", data_iptype->ipv4_addr_gw);
+			IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
+							data_iptype->ipv6_addr_gw[0], data_iptype->ipv6_addr_gw[1], data_iptype->ipv6_addr_gw[2], data_iptype->ipv6_addr_gw[3]);
+#endif
+			IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", data_iptype->if_index,
+					data_iptype->if_index_tether, data_iptype->iptype);
+			evt_data.event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
+			evt_data.evt_data = data_iptype;
+			break;
+		case WAN_UPSTREAM_ROUTE_DEL:
+			memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+			IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
+			data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
+			if(data_iptype == NULL)
+			{
+				IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
+			ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
+			data_iptype->iptype = event_wan.ip;
+			IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) ip-type(%d)\n", data_iptype->if_index, data_iptype->iptype);
+			evt_data.event = IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT;
+			evt_data.evt_data = data_iptype;
+			break;
+		/* End of adding for 8994 Android case */
+
+		/* Add for embms case */
+		case WAN_EMBMS_CONNECT:
+			memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+			IPACMDBG("Received WAN_EMBMS_CONNECT name: %s\n",event_wan.upstream_ifname);
+			data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_fid\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+			evt_data.event = IPA_WAN_EMBMS_LINK_UP_EVENT;
+			evt_data.evt_data = data_fid;
+			break;
+
+		case WLAN_SWITCH_TO_SCC:
+			IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
+		case WLAN_WDI_ENABLE:
+			IPACMDBG_H("Received WLAN_WDI_ENABLE\n");
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+			{
+				IPACM_Iface::ipacmcfg->isMCC_Mode = false;
+				evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
+				break;
+			}
+			continue;
+		case WLAN_SWITCH_TO_MCC:
+			IPACMDBG_H("Received WLAN_SWITCH_TO_MCC\n");
+		case WLAN_WDI_DISABLE:
+			IPACMDBG_H("Received WLAN_WDI_DISABLE\n");
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode == false)
+			{
+				IPACM_Iface::ipacmcfg->isMCC_Mode = true;
+				evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
+				break;
+			}
+			continue;
+
+		case WAN_XLAT_CONNECT:
+			memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta),
+				sizeof(struct ipa_wan_msg));
+			IPACMDBG_H("Received WAN_XLAT_CONNECT name: %s\n",
+					event_wan.upstream_ifname);
+
+			/* post IPA_LINK_UP_EVENT event
+			 * may be WAN interface is not up
+			*/
+			data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for xlat event\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+			evt_data.event = IPA_LINK_UP_EVENT;
+			evt_data.evt_data = data_fid;
+			IPACMDBG_H("Posting IPA_LINK_UP_EVENT event:%d\n", evt_data.event);
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+			/* post IPA_WAN_XLAT_CONNECT_EVENT event */
+			memset(&evt_data, 0, sizeof(evt_data));
+			data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
+			if(data_fid == NULL)
+			{
+				IPACMERR("unable to allocate memory for xlat event\n");
+				return NULL;
+			}
+			ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+			evt_data.event = IPA_WAN_XLAT_CONNECT_EVENT;
+			evt_data.evt_data = data_fid;
+			IPACMDBG_H("Posting IPA_WAN_XLAT_CONNECT_EVENT event:%d\n", evt_data.event);
+			break;
+
+		case IPA_TETHERING_STATS_UPDATE_STATS:
+			memcpy(&event_data_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			data_tethering_stats = (ipa_get_data_stats_resp_msg_v01 *)malloc(sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			if(data_tethering_stats == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_tethering_stats\n");
+				return NULL;
+			}
+			memcpy(data_tethering_stats,
+					 &event_data_stats,
+						 sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data_tethering_stats->ipa_stats_type);
+			IPACMDBG("Received %d UL, %d DL pipe stats\n",data_tethering_stats->ul_src_pipe_stats_list_len, data_tethering_stats->dl_dst_pipe_stats_list_len);
+			evt_data.event = IPA_TETHERING_STATS_UPDATE_EVENT;
+			evt_data.evt_data = data_tethering_stats;
+			break;
+
+		case IPA_TETHERING_STATS_UPDATE_NETWORK_STATS:
+			memcpy(&event_network_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+			data_network_stats = (ipa_get_apn_data_stats_resp_msg_v01 *)malloc(sizeof(ipa_get_apn_data_stats_resp_msg_v01));
+			if(data_network_stats == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_network_stats\n");
+				return NULL;
+			}
+			memcpy(data_network_stats,
+					 &event_network_stats,
+						 sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+			IPACMDBG("Received %d apn network stats \n", data_network_stats->apn_data_stats_list_len);
+			evt_data.event = IPA_NETWORK_STATS_UPDATE_EVENT;
+			evt_data.evt_data = data_network_stats;
+			break;
+
+		default:
+			IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
+			continue;
+
+		}
+		/* finish command queue */
+		IPACMDBG_H("Posting event:%d\n", evt_data.event);
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+		/* push new_neighbor with netdev device internally */
+		if(new_neigh_data != NULL)
+		{
+			IPACMDBG_H("Internally post event IPA_NEW_NEIGH_EVENT\n");
+			IPACM_EvtDispatcher::PostEvt(&new_neigh_evt);
+		}
+	}
+
+	(void)close(fd);
+	return NULL;
+}
+
+void IPACM_Sig_Handler(int sig)
+{
+	int cnt;
+	ipacm_cmd_q_data evt_data;
+
+	printf("Received Signal: %d\n", sig);
+	memset(&evt_data, 0, sizeof(evt_data));
+
+	switch(sig)
+	{
+		case SIGUSR1:
+			IPACMDBG_H("Received SW_ROUTING_ENABLE request \n");
+			evt_data.event = IPA_SW_ROUTING_ENABLE;
+			IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = true;
+			break;
+
+		case SIGUSR2:
+			IPACMDBG_H("Received SW_ROUTING_DISABLE request \n");
+			evt_data.event = IPA_SW_ROUTING_DISABLE;
+			IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = false;
+			break;
+	}
+	/* finish command queue */
+	IPACMDBG_H("Posting event:%d\n", evt_data.event);
+	IPACM_EvtDispatcher::PostEvt(&evt_data);
+	return;
+}
+
+void RegisterForSignals(void)
+{
+
+	signal(SIGUSR1, IPACM_Sig_Handler);
+	signal(SIGUSR2, IPACM_Sig_Handler);
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret;
+	pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
+	pthread_t cmd_queue_thread = 0;
+
+	/* check if ipacm is already running or not */
+	ipa_is_ipacm_running();
+
+	IPACMDBG_H("In main()\n");
+	IPACM_Neighbor *neigh = new IPACM_Neighbor();
+	IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
+
+#ifdef FEATURE_ETH_BRIDGE_LE
+	IPACM_LanToLan* lan2lan = new IPACM_LanToLan();
+#endif
+
+	IPACM_ConntrackClient *cc = IPACM_ConntrackClient::GetInstance();
+	CtList = new IPACM_ConntrackListener();
+
+	IPACMDBG_H("Staring IPA main\n");
+	IPACMDBG_H("ipa_cmdq_successful\n");
+
+
+	RegisterForSignals();
+
+	if (IPACM_SUCCESS == cmd_queue_thread)
+	{
+		ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to command queue thread\n");
+			return ret;
+		}
+		IPACMDBG_H("created command queue thread\n");
+		if(pthread_setname_np(cmd_queue_thread, "cmd queue process") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
+	}
+
+	if (IPACM_SUCCESS == netlink_thread)
+	{
+		ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create netlink thread\n");
+			return ret;
+		}
+		IPACMDBG_H("created netlink thread\n");
+		if(pthread_setname_np(netlink_thread, "netlink socket") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
+	}
+
+	/* Enable Firewall support only on MDM targets */
+#ifndef FEATURE_IPA_ANDROID
+	if (IPACM_SUCCESS == monitor_thread)
+	{
+		ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create monitor thread\n");
+			return ret;
+		}
+		IPACMDBG_H("created firewall monitor thread\n");
+		if(pthread_setname_np(monitor_thread, "firewall cfg process") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
+	}
+#endif
+
+	if (IPACM_SUCCESS == ipa_driver_thread)
+	{
+		ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_msg_notifier, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create ipa_driver_wlan thread\n");
+			return ret;
+		}
+		IPACMDBG_H("created ipa_driver_wlan thread\n");
+		if(pthread_setname_np(ipa_driver_thread, "ipa driver ntfy") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
+	}
+
+	pthread_join(cmd_queue_thread, NULL);
+	pthread_join(netlink_thread, NULL);
+	pthread_join(monitor_thread, NULL);
+	pthread_join(ipa_driver_thread, NULL);
+	return IPACM_SUCCESS;
+}
+
+/*===========================================================================
+		FUNCTION  ipa_is_ipacm_running
+===========================================================================*/
+/*!
+@brief
+  Determine whether there's already an IPACM process running, if so, terminate
+  the current one
+
+@return
+	None
+
+@note
+
+- Dependencies
+		- None
+
+- Side Effects
+		- None
+*/
+/*=========================================================================*/
+
+void ipa_is_ipacm_running(void) {
+
+	int fd;
+	struct flock lock;
+	int retval;
+
+	fd = open(IPACM_PID_FILE, O_RDWR | O_CREAT, 0600);
+	if ( fd <= 0 )
+	{
+		IPACMERR("Failed to open %s, error is %d - %s\n",
+				 IPACM_PID_FILE, errno, strerror(errno));
+		exit(0);
+	}
+
+	/*
+	 * Getting an exclusive Write lock on the file, if it fails,
+	 * it means that another instance of IPACM is running and it
+	 * got the lock before us.
+	 */
+	memset(&lock, 0, sizeof(lock));
+	lock.l_type = F_WRLCK;
+	retval = fcntl(fd, F_SETLK, &lock);
+
+	if (retval != 0)
+	{
+		retval = fcntl(fd, F_GETLK, &lock);
+		if (retval == 0)
+		{
+			IPACMERR("Unable to get lock on file %s (my PID %d), PID %d already has it\n",
+					 IPACM_PID_FILE, getpid(), lock.l_pid);
+			close(fd);
+			exit(0);
+		}
+	}
+	else
+	{
+		IPACMERR("PID %d is IPACM main process\n", getpid());
+	}
+
+	return;
+}
+
+/*===========================================================================
+		FUNCTION  ipa_get_if_index
+===========================================================================*/
+/*!
+@brief
+  get ipa interface index by given the interface name
+
+@return
+	IPACM_SUCCESS or IPA_FALUIRE
+
+@note
+
+- Dependencies
+		- None
+
+- Side Effects
+		- None
+*/
+/*=========================================================================*/
+int ipa_get_if_index
+(
+	 char *if_name,
+	 int *if_index
+	 )
+{
+	int fd;
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface index socket create failed");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	(void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+
+	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+	{
+		IPACMERR("call_ioctl_on_dev: ioctl failed: can't find device %s",if_name);
+		*if_index = -1;
+		close(fd);
+		return IPACM_FAILURE;
+	}
+
+	*if_index = ifr.ifr_ifindex;
+	close(fd);
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
new file mode 100644
index 0000000..5a72c4c
--- /dev/null
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -0,0 +1,570 @@
+/*
+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_Neighbor.cpp
+
+	@brief
+	This file implements the functionality of handling IPACM Neighbor events.
+
+	@Author
+	Skylar Chang
+
+*/
+
+#include <sys/ioctl.h>
+#include <IPACM_Neighbor.h>
+#include <IPACM_EvtDispatcher.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Log.h"
+
+
+IPACM_Neighbor::IPACM_Neighbor()
+{
+	num_neighbor_client = 0;
+	circular_index = 0;
+	memset(neighbor_client, 0, IPA_MAX_NUM_NEIGHBOR_CLIENTS * sizeof(ipa_neighbor_client));
+	IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, this);
+	IPACM_EvtDispatcher::registr(IPA_NEW_NEIGH_EVENT, this);
+	IPACM_EvtDispatcher::registr(IPA_DEL_NEIGH_EVENT, this);
+	return;
+}
+
+void IPACM_Neighbor::event_callback(ipa_cm_event_id event, void *param)
+{
+	ipacm_event_data_all *data_all = NULL;
+	int i, ipa_interface_index;
+	ipacm_cmd_q_data evt_data;
+	int num_neighbor_client_temp = num_neighbor_client;
+
+	IPACMDBG("Recieved event %d\n", event);
+
+	switch (event)
+	{
+		case IPA_WLAN_CLIENT_ADD_EVENT_EX:
+		{
+			ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_CLIENT_ADD_EVENT_EX: not supported iface id: %d\n", data->if_index);
+				break;
+			}
+			uint8_t client_mac_addr[6];
+
+			IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+			for(i = 0; i < data->num_of_attribs; i++)
+			{
+				if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+				{
+					memcpy(client_mac_addr,
+							data->attribs[i].u.mac_addr,
+							sizeof(client_mac_addr));
+					IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 client_mac_addr[0], client_mac_addr[1], client_mac_addr[2],
+							 client_mac_addr[3], client_mac_addr[4], client_mac_addr[5]);
+				}
+				else
+				{
+					IPACMDBG_H("The attribute type is not expected!\n");
+				}
+			}
+
+			for (i = 0; i < num_neighbor_client_temp; i++)
+			{
+				/* find the client */
+				if (memcmp(neighbor_client[i].mac_addr, client_mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+				{
+					/* check if iface is not bridge interface*/
+					if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+					{
+						/* use previous ipv4 first */
+						if(data->if_index != neighbor_client[i].iface_index)
+						{
+							IPACMERR("update new kernel iface index \n");
+							neighbor_client[i].iface_index = data->if_index;
+						}
+
+						/* check if client associated with previous network interface */
+						if(ipa_interface_index != neighbor_client[i].ipa_if_num)
+						{
+							IPACMERR("client associate to different AP \n");
+							return;
+						}
+
+						if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
+						{
+							evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+							data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+							if (data_all == NULL)
+							{
+								IPACMERR("Unable to allocate memory\n");
+								return;
+							}
+							data_all->iptype = IPA_IP_v4;
+							data_all->if_index = neighbor_client[i].iface_index;
+							data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
+							memcpy(data_all->mac_addr,
+									neighbor_client[i].mac_addr,
+												sizeof(data_all->mac_addr));
+							evt_data.evt_data = (void *)data_all;
+							IPACM_EvtDispatcher::PostEvt(&evt_data);
+							/* ask for replaced iface name*/
+							ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+							/* check for failure return */
+							if (IPACM_FAILURE == ipa_interface_index) {
+								IPACMERR("not supported iface id: %d\n", data_all->if_index);
+							} else {
+								IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
+									evt_data.event,
+									IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+							}
+						}
+					}
+					break;
+				}
+			}
+		}
+		break;
+
+		default:
+		{
+			if (event == IPA_NEW_NEIGH_EVENT)
+			{
+				IPACMDBG_H("Received IPA_NEW_NEIGH_EVENT\n");
+			}
+			else
+			{
+				IPACMDBG_H("Received IPA_DEL_NEIGH_EVENT\n");
+			}
+
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("not supported iface id: %d\n", data->if_index);
+				break;
+			}
+			if (data->iptype == IPA_IP_v4)
+			{
+				if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+				{
+					IPACMDBG("Got Neighbor event with ipv4 address: 0x%x \n", data->ipv4_addr);
+					/* check if ipv4 address is link local(169.254.xxx.xxx) */
+					if ((data->ipv4_addr & IPV4_ADDR_LINKLOCAL_MASK) == IPV4_ADDR_LINKLOCAL)
+					{
+						IPACMDBG_H("This is link local ipv4 address: 0x%x : ignore this NEIGH_EVENT\n", data->ipv4_addr);
+						return;
+					}
+					/* check if iface is bridge interface*/
+					if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+					{
+						/* searh if seen this client or not*/
+						for (i = 0; i < num_neighbor_client_temp; i++)
+						{
+							if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+							{
+								data->if_index = neighbor_client[i].iface_index;
+								neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
+								/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+								if (event == IPA_NEW_NEIGH_EVENT)
+									evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+								else
+									/* not to clean-up the client mac cache on bridge0 delneigh */
+									evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+								data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+								if (data_all == NULL)
+								{
+									IPACMERR("Unable to allocate memory\n");
+									return;
+								}
+								memcpy(data_all, data, sizeof(ipacm_event_data_all));
+								evt_data.evt_data = (void *)data_all;
+								IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+								/* ask for replaced iface name*/
+								ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+								/* check for failure return */
+								if (IPACM_FAILURE == ipa_interface_index) {
+									IPACMERR("not supported iface id: %d\n", data_all->if_index);
+								} else {
+									IPACMDBG_H("Posted event %d,\
+										with %s for ipv4\n",
+										evt_data.event,
+										IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								}
+								break;
+							}
+						}
+					}
+					else
+					{
+						/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+						if (event == IPA_NEW_NEIGH_EVENT)
+						{
+							evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+							/* Also save to cache for ipv4 */
+							/*searh if seen this client or not*/
+							for (i = 0; i < num_neighbor_client_temp; i++)
+							{
+								/* find the client */
+								if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+								{
+									/* update the network interface client associated */
+									neighbor_client[i].iface_index = data->if_index;
+									neighbor_client[i].ipa_if_num = ipa_interface_index;
+									neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
+									IPACMDBG_H("update cache %d-entry, with %s iface, ipv4 address: 0x%x\n",
+													i,
+													IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
+													data->ipv4_addr);
+									break;
+								}
+							}
+							/* not find client */
+							if (i == num_neighbor_client_temp)
+							{
+								if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+								{
+									memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+												data->mac_addr,
+												sizeof(data->mac_addr));
+									neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+									/* cache the network interface client associated */
+									neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
+									neighbor_client[num_neighbor_client_temp].v4_addr = data->ipv4_addr;
+									num_neighbor_client++;
+									IPACMDBG_H("Cache client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+												neighbor_client[num_neighbor_client_temp].mac_addr[0],
+												neighbor_client[num_neighbor_client_temp].mac_addr[1],
+												neighbor_client[num_neighbor_client_temp].mac_addr[2],
+												neighbor_client[num_neighbor_client_temp].mac_addr[3],
+												neighbor_client[num_neighbor_client_temp].mac_addr[4],
+												neighbor_client[num_neighbor_client_temp].mac_addr[5],
+												num_neighbor_client);
+								}
+								else
+								{
+
+									IPACMERR("error:  neighbor client oversize! recycle %d-st entry ! \n", circular_index);
+									memcpy(neighbor_client[circular_index].mac_addr,
+												data->mac_addr,
+												sizeof(data->mac_addr));
+									neighbor_client[circular_index].iface_index = data->if_index;
+									/* cache the network interface client associated */
+									neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
+									neighbor_client[circular_index].v4_addr = 0;
+									IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
+													neighbor_client[circular_index].mac_addr[0],
+													neighbor_client[circular_index].mac_addr[1],
+													neighbor_client[circular_index].mac_addr[2],
+													neighbor_client[circular_index].mac_addr[3],
+													neighbor_client[circular_index].mac_addr[4],
+													neighbor_client[circular_index].mac_addr[5],
+													num_neighbor_client,
+													circular_index);
+									circular_index++;
+								}
+							}
+						}
+						else
+						{
+							evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+							/*searh if seen this client or not*/
+							for (i = 0; i < num_neighbor_client_temp; i++)
+							{
+								/* find the client */
+								if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+								{
+									IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+												i,
+												neighbor_client[i].mac_addr[0],
+												neighbor_client[i].mac_addr[1],
+												neighbor_client[i].mac_addr[2],
+												neighbor_client[i].mac_addr[3],
+												neighbor_client[i].mac_addr[4],
+												neighbor_client[i].mac_addr[5],
+												num_neighbor_client);
+
+									memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
+									neighbor_client[i].iface_index = 0;
+									neighbor_client[i].v4_addr = 0;
+									neighbor_client[i].ipa_if_num = 0;
+									for (; i < num_neighbor_client_temp - 1; i++)
+									{
+										memcpy(neighbor_client[i].mac_addr,
+													neighbor_client[i+1].mac_addr,
+													sizeof(neighbor_client[i].mac_addr));
+										neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
+										neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
+										neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
+									}
+									num_neighbor_client--;
+									IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
+									break;
+								}
+							}
+							/* not find client, no need clean-up */
+						}
+
+						data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+						if (data_all == NULL)
+						{
+							IPACMERR("Unable to allocate memory\n");
+							return;
+						}
+						memcpy(data_all, data, sizeof(ipacm_event_data_all));
+						evt_data.evt_data = (void *)data_all;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						IPACMDBG_H("Posted event %d with %s for ipv4\n",
+									evt_data.event,
+									IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					}
+				}
+			}
+			else
+			{   //ipv6 starts
+
+				if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
+				{
+					IPACMDBG("Got New_Neighbor event with ipv6 address \n");
+					/* check if iface is bridge interface*/
+					if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+					{
+						/* searh if seen this client or not*/
+						for (i = 0; i < num_neighbor_client_temp; i++)
+						{
+							if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+							{
+								data->if_index = neighbor_client[i].iface_index;
+								/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+								if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+								else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+								data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+								if (data_all == NULL)
+								{
+									IPACMERR("Unable to allocate memory\n");
+									return;
+								}
+								memcpy(data_all, data, sizeof(ipacm_event_data_all));
+								evt_data.evt_data = (void *)data_all;
+								IPACM_EvtDispatcher::PostEvt(&evt_data);
+								/* ask for replaced iface name*/
+								ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+								/* check for failure return */
+								if (IPACM_FAILURE == ipa_interface_index) {
+									IPACMERR("not supported iface id: %d\n", data_all->if_index);
+								} else {
+									IPACMDBG_H("Posted event %d,\
+										with %s for ipv6\n",
+										evt_data.event,
+										IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								}
+								break;
+							};
+						}
+					}
+					else
+					{
+						/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+						if (event == IPA_NEW_NEIGH_EVENT)
+							evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+						else
+							evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+						data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+						if (data_all == NULL)
+						{
+							IPACMERR("Unable to allocate memory\n");
+							return;
+						}
+						memcpy(data_all, data, sizeof(ipacm_event_data_all));
+						evt_data.evt_data = (void *)data_all;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						IPACMDBG_H("Posted event %d with %s for ipv6\n",
+										evt_data.event,
+										IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					}
+				}
+				else
+				{
+					IPACMDBG(" Got Neighbor event with no ipv6/ipv4 address \n");
+					/*no ipv6 in data searh if seen this client or not*/
+					for (i = 0; i < num_neighbor_client_temp; i++)
+					{
+						/* find the client */
+						if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+						{
+							IPACMDBG_H(" find %d-st client, MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+												i,
+												neighbor_client[i].mac_addr[0],
+												neighbor_client[i].mac_addr[1],
+												neighbor_client[i].mac_addr[2],
+												neighbor_client[i].mac_addr[3],
+												neighbor_client[i].mac_addr[4],
+												neighbor_client[i].mac_addr[5],
+												num_neighbor_client);
+							/* check if iface is not bridge interface*/
+							if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+							{
+								/* use previous ipv4 first */
+								if(data->if_index != neighbor_client[i].iface_index)
+								{
+									IPACMDBG_H("update new kernel iface index \n");
+									neighbor_client[i].iface_index = data->if_index;
+								}
+
+								/* check if client associated with previous network interface */
+								if(ipa_interface_index != neighbor_client[i].ipa_if_num)
+								{
+									IPACMDBG_H("client associate to different AP \n");
+								}
+
+								if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
+								{
+									/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+									if (event == IPA_NEW_NEIGH_EVENT)
+										evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+									else
+										evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+									data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+									if (data_all == NULL)
+									{
+										IPACMERR("Unable to allocate memory\n");
+										return;
+									}
+									data_all->iptype = IPA_IP_v4;
+									data_all->if_index = neighbor_client[i].iface_index;
+									data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
+									memcpy(data_all->mac_addr,
+											neighbor_client[i].mac_addr,
+														sizeof(data_all->mac_addr));
+									evt_data.evt_data = (void *)data_all;
+									IPACM_EvtDispatcher::PostEvt(&evt_data);
+									/* ask for replaced iface name*/
+									ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+									/* check for failure return */
+									if (IPACM_FAILURE == ipa_interface_index) {
+										IPACMERR("not supported iface id: %d\n", data_all->if_index);
+									} else {
+										IPACMDBG_H("Posted event %d,\
+											with %s for ipv4 client re-connect\n",
+											evt_data.event,
+											IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+									}
+								}
+							}
+							/* delete cache neighbor entry */
+							if (event == IPA_DEL_NEIGH_EVENT)
+							{
+								IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+										i,
+										neighbor_client[i].mac_addr[0],
+										neighbor_client[i].mac_addr[1],
+										neighbor_client[i].mac_addr[2],
+										neighbor_client[i].mac_addr[3],
+										neighbor_client[i].mac_addr[4],
+										neighbor_client[i].mac_addr[5],
+										num_neighbor_client);
+
+								memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
+								neighbor_client[i].iface_index = 0;
+								neighbor_client[i].v4_addr = 0;
+								neighbor_client[i].ipa_if_num = 0;
+								for (; i < num_neighbor_client_temp - 1; i++)
+								{
+									memcpy(neighbor_client[i].mac_addr,
+												neighbor_client[i+1].mac_addr,
+												sizeof(neighbor_client[i].mac_addr));
+									neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
+									neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
+									neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
+								}
+								num_neighbor_client--;
+								IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
+							}
+							break;
+						}
+					}
+					/* not find client */
+					if ((i == num_neighbor_client_temp) && (event == IPA_NEW_NEIGH_EVENT))
+					{
+						/* check if iface is not bridge interface*/
+						if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+						{
+							if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+							{
+								memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+											data->mac_addr,
+											sizeof(data->mac_addr));
+								neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+								/* cache the network interface client associated */
+								neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
+								neighbor_client[num_neighbor_client_temp].v4_addr = 0;
+								num_neighbor_client++;
+								IPACMDBG_H("Copy client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+												neighbor_client[num_neighbor_client_temp].mac_addr[0],
+												neighbor_client[num_neighbor_client_temp].mac_addr[1],
+												neighbor_client[num_neighbor_client_temp].mac_addr[2],
+												neighbor_client[num_neighbor_client_temp].mac_addr[3],
+												neighbor_client[num_neighbor_client_temp].mac_addr[4],
+												neighbor_client[num_neighbor_client_temp].mac_addr[5],
+												num_neighbor_client);
+								return;
+							}
+							else
+							{
+								IPACMERR("error:  neighbor client oversize! recycle %d-st entry ! \n", circular_index);
+								memcpy(neighbor_client[circular_index].mac_addr,
+											data->mac_addr,
+											sizeof(data->mac_addr));
+								neighbor_client[circular_index].iface_index = data->if_index;
+								/* cache the network interface client associated */
+								neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
+								neighbor_client[circular_index].v4_addr = 0;
+								IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
+												neighbor_client[circular_index].mac_addr[0],
+												neighbor_client[circular_index].mac_addr[1],
+												neighbor_client[circular_index].mac_addr[2],
+												neighbor_client[circular_index].mac_addr[3],
+												neighbor_client[circular_index].mac_addr[4],
+												neighbor_client[circular_index].mac_addr[5],
+												num_neighbor_client,
+												circular_index);
+								circular_index++;
+								return;
+							}
+						}
+					}
+				}
+			} //ipv6 ends
+		}
+		break;
+	}
+	return;
+}
diff --git a/ipacm/src/IPACM_Netlink.cpp b/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..30295b1
--- /dev/null
+++ b/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1773 @@
+/*
+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_Netlink.cpp
+
+	@brief
+	This file implements the IPAM Netlink Socket Parer functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Netlink.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Log.h"
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#ifdef FEATURE_IPA_ANDROID
+
+#define IPACM_NL_COPY_ADDR( event_info, element )                                        \
+        memcpy( &event_info->attr_info.element.__data,                                   \
+                RTA_DATA(rtah),                                                          \
+                sizeof(event_info->attr_info.element.__data) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element)                                   \
+        memcpy( event_data, element.__data, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element)                                   \
+        memcpy( &event_data, element.__data, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr )                                             \
+        if( AF_INET6 == (addr).ss_family ) {                                             \
+          IPACM_LOG_IPV6_ADDR( prefix, addr.__data);                                    \
+        } else {                                                                         \
+          IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__data) );               \
+        }
+
+#else/* defined(FEATURE_IPA_ANDROID) */
+
+#define IPACM_NL_COPY_ADDR( event_info, element )                                        \
+        memcpy( &event_info->attr_info.element.__ss_padding,                             \
+                RTA_DATA(rtah),                                                          \
+                sizeof(event_info->attr_info.element.__ss_padding) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element)                                   \
+        memcpy( event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element)                                   \
+        memcpy( &event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr )                                             \
+        if( AF_INET6 == (addr).ss_family ) {                                             \
+          IPACM_LOG_IPV6_ADDR( prefix, addr.__ss_padding);                               \
+        } else {                                                                         \
+          IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__ss_padding) );         \
+        }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define IPACM_LOG_IPV6_ADDR(prefix, ip_addr)                            \
+        IPACMDBG_H(prefix);                                               \
+		IPACMDBG_H(" IPV6 Address %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", \
+                  (int)ip_addr[0],  (int)ip_addr[1],                                                        \
+                  (int)ip_addr[2],  (int)ip_addr[3],                                                        \
+                  (int)ip_addr[4],  (int)ip_addr[5],                                                        \
+                  (int)ip_addr[6],  (int)ip_addr[7],                                                        \
+                  (int)ip_addr[8],  (int)ip_addr[9],                                                        \
+                  (int)ip_addr[10], (int)ip_addr[11],                                                       \
+                  (int)ip_addr[12], (int)ip_addr[13],                                                       \
+                  (int)ip_addr[14], (int)ip_addr[15]);
+
+#define IPACM_LOG_IPV4_ADDR(prefix, ip_addr)                            \
+        IPACMDBG_H(prefix);                                               \
+        IPACMDBG_H(" IPV4 Address %d.%d.%d.%d\n",                         \
+                    (unsigned char)(ip_addr),                               \
+                    (unsigned char)(ip_addr >> 8),                          \
+                    (unsigned char)(ip_addr >> 16) ,                        \
+                    (unsigned char)(ip_addr >> 24));
+
+/* Opens a netlink socket*/
+static int ipa_nl_open_socket
+(
+	 ipa_nl_sk_info_t *sk_info,
+	 int protocol,
+	 unsigned int grps
+	 )
+{
+	int *p_sk_fd;
+	int buf_size = 6669999, sendbuff=0, res;
+	struct sockaddr_nl *p_sk_addr_loc;
+	socklen_t optlen;
+
+	p_sk_fd = &(sk_info->sk_fd);
+	p_sk_addr_loc = &(sk_info->sk_addr_loc);
+
+	/* Open netlink socket for specified protocol */
+	if((*p_sk_fd = socket(AF_NETLINK, SOCK_RAW, protocol)) < 0)
+	{
+		IPACMERR("cannot open netlink socket\n");
+		return IPACM_FAILURE;
+	}
+
+	optlen = sizeof(sendbuff);
+	res = getsockopt(*p_sk_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
+
+	if(res == -1) {
+		IPACMDBG("Error getsockopt one");
+	} else {
+		IPACMDBG("orignal send buffer size = %d\n", sendbuff);
+	}
+	IPACMDBG("sets the send buffer to %d\n", buf_size);
+	if (setsockopt(*p_sk_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(int)) == -1) {
+    IPACMERR("Error setting socket opts\n");
+	}
+
+	/* Initialize socket addresses to null */
+	memset(p_sk_addr_loc, 0, sizeof(struct sockaddr_nl));
+
+	/* Populate local socket address using specified groups */
+	p_sk_addr_loc->nl_family = AF_NETLINK;
+	p_sk_addr_loc->nl_pid = getpid();
+	p_sk_addr_loc->nl_groups = grps;
+
+	/* Bind socket to the local address, i.e. specified groups. This ensures
+	 that multicast messages for these groups are delivered over this
+	 socket. */
+
+	if(bind(*p_sk_fd,
+					(struct sockaddr *)p_sk_addr_loc,
+					sizeof(struct sockaddr_nl)) < 0)
+	{
+		IPACMERR("Socket bind failed\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Add fd to fdmap array and store read handler function ptr (up to MAX_NUM_OF_FD).*/
+static int ipa_nl_addfd_map
+(
+	 ipa_nl_sk_fd_set_info_t *info,
+	 int fd,
+	 ipa_sock_thrd_fd_read_f read_f
+	 )
+{
+	if(info->num_fd < MAX_NUM_OF_FD)
+	{
+		FD_SET(fd, &info->fdset);
+
+		/* Add fd to fdmap array and store read handler function ptr */
+		info->sk_fds[info->num_fd].sk_fd = fd;
+		info->sk_fds[info->num_fd].read_func = read_f;
+
+		/* Increment number of fds stored in fdmap */
+		info->num_fd++;
+		if(info->max_fd < fd)
+			info->max_fd = fd;
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*  start socket listener */
+static int ipa_nl_sock_listener_start
+(
+	 ipa_nl_sk_fd_set_info_t *sk_fd_set
+	 )
+{
+	int i, ret;
+
+	while(true)
+	{
+	    for(i = 0; i < sk_fd_set->num_fd; i++ )
+		{
+			FD_SET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+		}
+
+		if((ret = select(sk_fd_set->max_fd + 1, &(sk_fd_set->fdset), NULL, NULL, NULL)) < 0)
+		{
+			IPACMERR("ipa_nl select failed\n");
+		}
+		else
+		{
+			for(i = 0; i < sk_fd_set->num_fd; i++)
+			{
+
+				if(FD_ISSET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset)))
+				{
+
+					if(sk_fd_set->sk_fds[i].read_func)
+					{
+						if(IPACM_SUCCESS != ((sk_fd_set->sk_fds[i].read_func)(sk_fd_set->sk_fds[i].sk_fd)))
+						{
+							IPACMERR("Error on read callback[%d] fd=%d\n",
+											 i,
+											 sk_fd_set->sk_fds[i].sk_fd);
+						}
+						FD_CLR(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+					}
+					else
+					{
+						IPACMERR("No read function\n");
+					}
+				}
+
+			} /* end of for loop*/
+		} /* end of else */
+	} /* end of while */
+
+	return IPACM_SUCCESS;
+}
+
+/* allocate memory for ipa_nl__msg */
+static struct msghdr* ipa_nl_alloc_msg
+(
+	 uint32_t msglen
+	 )
+{
+	unsigned char *buf = NULL;
+	struct sockaddr_nl *nladdr = NULL;
+	struct iovec *iov = NULL;
+	struct msghdr *msgh = NULL;
+
+	if(IPA_NL_MSG_MAX_LEN < msglen)
+	{
+		IPACMERR("Netlink message exceeds maximum length\n");
+		return NULL;
+	}
+
+	msgh = (struct msghdr *)malloc(sizeof(struct msghdr));
+	if(msgh == NULL)
+	{
+		IPACMERR("Failed malloc for msghdr\n");
+		return NULL;
+	}
+
+	nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+	if(nladdr == NULL)
+	{
+		IPACMERR("Failed malloc for sockaddr\n");
+		free(msgh);
+		return NULL;
+	}
+
+	iov = (struct iovec *)malloc(sizeof(struct iovec));
+	if(iov == NULL)
+	{
+		PERROR("Failed malloc for iovec");
+		free(nladdr);
+		free(msgh);
+		return NULL;
+	}
+
+	buf = (unsigned char *)malloc(msglen);
+	if(buf == NULL)
+	{
+		IPACMERR("Failed malloc for mglen\n");
+		free(iov);
+		free(nladdr);
+		free(msgh);
+		return NULL;
+	}
+
+	memset(nladdr, 0, sizeof(struct sockaddr_nl));
+	nladdr->nl_family = AF_NETLINK;
+
+	memset(msgh, 0x0, sizeof(struct msghdr));
+	msgh->msg_name = nladdr;
+	msgh->msg_namelen = sizeof(struct sockaddr_nl);
+	msgh->msg_iov = iov;
+	msgh->msg_iovlen = 1;
+
+	memset(iov, 0x0, sizeof(struct iovec));
+	iov->iov_base = buf;
+	iov->iov_len = msglen;
+
+	return msgh;
+}
+
+/* release IPA message */
+static void ipa_nl_release_msg
+(
+	 struct msghdr *msgh
+	 )
+{
+	unsigned char *buf = NULL;
+	struct sockaddr_nl *nladdr = NULL;
+	struct iovec *iov = NULL;
+
+	if(NULL == msgh)
+	{
+		return;
+	}
+
+	nladdr = (struct sockaddr_nl *)msgh->msg_name;
+	iov = msgh->msg_iov;
+	if(msgh->msg_iov)
+	{
+		buf = (unsigned char *)msgh->msg_iov->iov_base;
+	}
+
+	if(buf)
+	{
+	free(buf);
+	}
+	if(iov)
+	{
+	free(iov);
+	}
+	if(nladdr)
+	{
+	free(nladdr);
+	}
+	if(msgh)
+	{
+	free(msgh);
+	}
+	return;
+}
+
+/* receive and process nl message */
+static int ipa_nl_recv
+(
+	 int              fd,
+	 struct msghdr **msg_pptr,
+	 unsigned int  *msglen_ptr
+	 )
+{
+	struct msghdr *msgh = NULL;
+	int rmsgl;
+
+	msgh = ipa_nl_alloc_msg(IPA_NL_MSG_MAX_LEN);
+	if(NULL == msgh)
+	{
+		IPACMERR("Failed to allocate NL message\n");
+		goto error;
+	}
+
+
+	/* Receive message over the socket */
+	rmsgl = recvmsg(fd, msgh, 0);
+
+	/* Verify that something was read */
+	if(rmsgl <= 0)
+	{
+		PERROR("NL recv error");
+		goto error;
+	}
+
+	/* Verify that NL address length in the received message is expected value */
+	if(sizeof(struct sockaddr_nl) != msgh->msg_namelen)
+	{
+		IPACMERR("rcvd msg with namelen != sizeof sockaddr_nl\n");
+		goto error;
+	}
+
+	/* Verify that message was not truncated. This should not occur */
+	if(msgh->msg_flags & MSG_TRUNC)
+	{
+		IPACMERR("Rcvd msg truncated!\n");
+		goto error;
+	}
+
+	*msg_pptr    = msgh;
+	*msglen_ptr = rmsgl;
+
+	return IPACM_SUCCESS;
+
+/* An error occurred while receiving the message. Free all memory before
+				 returning. */
+error:
+	ipa_nl_release_msg(msgh);
+	*msg_pptr    = NULL;
+	*msglen_ptr  = 0;
+
+	return IPACM_FAILURE;
+}
+
+/* decode the rtm netlink message */
+static int ipa_nl_decode_rtm_link
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_link_info_t      *link_info
+)
+{
+	struct rtattr;
+	/* NL message header */
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+	/* Extract the header data */
+	link_info->metainfo = *(struct ifinfomsg *)NLMSG_DATA(nlh);
+	buflen -= sizeof(struct nlmsghdr);
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel address message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_addr
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_addr_info_t   *addr_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+
+	/* Extract the header data */
+	addr_info->metainfo = *((struct ifaddrmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	/* Extract the available attributes */
+	addr_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+	rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case IFA_ADDRESS:
+			addr_info->attr_info.prefix_addr.ss_family = addr_info->metainfo.ifa_family;
+			IPACM_NL_COPY_ADDR( addr_info, prefix_addr );
+			addr_info->attr_info.param_mask |= IPA_NLA_PARAM_PREFIXADDR;
+			break;
+		default:
+			break;
+
+		}
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel neighbor message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_neigh
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_neigh_info_t   *neigh_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+
+	/* Extract the header data */
+	neigh_info->metainfo = *((struct ndmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	/* Extract the available attributes */
+	neigh_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+	rtah = NDA_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case NDA_DST:
+			neigh_info->attr_info.local_addr.ss_family = neigh_info->metainfo.ndm_family;
+			IPACM_NL_COPY_ADDR( neigh_info, local_addr );
+			break;
+
+		case NDA_LLADDR:
+			memcpy(neigh_info->attr_info.lladdr_hwaddr.sa_data,
+						 RTA_DATA(rtah),
+						 sizeof(neigh_info->attr_info.lladdr_hwaddr.sa_data));
+			break;
+
+		default:
+			break;
+
+		}
+
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel route message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_route
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_route_info_t   *route_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+
+	/* Extract the header data */
+	route_info->metainfo = *((struct rtmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	route_info->attr_info.param_mask = IPA_RTA_PARAM_NONE;
+	rtah = RTM_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case RTA_DST:
+				route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+				IPACM_NL_COPY_ADDR( route_info, dst_addr );
+				route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+			break;
+
+		case RTA_SRC:
+			route_info->attr_info.src_addr.ss_family = route_info->metainfo.rtm_family;
+			IPACM_NL_COPY_ADDR( route_info, src_addr );
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_SRC;
+			break;
+
+		case RTA_GATEWAY:
+			route_info->attr_info.gateway_addr.ss_family = route_info->metainfo.rtm_family;
+			IPACM_NL_COPY_ADDR( route_info, gateway_addr );
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_GATEWAY;
+			break;
+
+		case RTA_IIF:
+			memcpy(&route_info->attr_info.iif_index,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.iif_index));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_IIF;
+			break;
+
+		case RTA_OIF:
+			memcpy(&route_info->attr_info.oif_index,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.oif_index));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_OIF;
+			break;
+
+		case RTA_PRIORITY:
+			memcpy(&route_info->attr_info.priority,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.priority));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_PRIORITY;
+			break;
+
+		default:
+			break;
+
+		}
+
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* decode the ipa nl-message */
+static int ipa_nl_decode_nlmsg
+(
+	 const char   *buffer,
+	 unsigned int  buflen,
+	 ipa_nl_msg_t  *msg_ptr
+	 )
+{
+	char dev_name[IF_NAME_LEN]={0};
+	int ret_val, mask_value, mask_index, mask_value_v6;
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+	uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0, if_ipv4_addr_gw =0;
+
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_data_all *data_all;
+	ipacm_event_data_fid *data_fid;
+	ipacm_event_data_addr *data_addr;
+
+
+	while(NLMSG_OK(nlh, buflen))
+	{
+		memset(dev_name,0,IF_NAME_LEN);
+		IPACMDBG("Received msg:%d from netlink\n", nlh->nlmsg_type)
+		switch(nlh->nlmsg_type)
+		{
+		case RTM_NEWLINK:
+			msg_ptr->type = nlh->nlmsg_type;
+			msg_ptr->link_event = true;
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+			{
+				IPACMERR("Failed to decode rtm link message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("Got RTM_NEWLINK with below values\n");
+				IPACMDBG("RTM_NEWLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+				IPACMDBG("RTM_NEWLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+				IPACMDBG("RTM_NEWLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+				IPACMDBG("RTM_NEWLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+				/* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+				   but this should be processed in case of MDM for Ehernet interface.
+				*/
+#ifdef FEATURE_IPA_ANDROID
+				if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+				{
+					IPACMERR(" ignore this RTM_NEWLINK msg \n");
+					return IPACM_SUCCESS;
+				}
+#endif
+				if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+				{
+					IPACMDBG("GOT useful newlink event\n");
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+
+					data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+					if(data_fid == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_fid\n");
+						return IPACM_FAILURE;
+					}
+					data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+					if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+					{
+						IPACMDBG_H("Interface %s bring up with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+						/* post link up to command queue */
+						evt_data.event = IPA_LINK_UP_EVENT;
+						IPACMDBG_H("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+										 msg_ptr->nl_link_info.metainfo.ifi_index);
+					}
+					else
+					{
+						IPACMDBG_H("Interface %s bring down with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+						/* post link down to command queue */
+						evt_data.event = IPA_LINK_DOWN_EVENT;
+						IPACMDBG_H("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+										 data_fid->if_index);
+					}
+					evt_data.evt_data = data_fid;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+				}
+
+				/* Add IPACM support for ECM plug-in/plug_out */
+				/*--------------------------------------------------------------------------
+                                   Check if the interface is running.If its a RTM_NEWLINK and the interface
+                                    is running then it means that its a link up event
+                                ---------------------------------------------------------------------------*/
+                                if((msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_RUNNING) &&
+                                   (msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+                                {
+
+					data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+					if(data_fid == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_fid\n");
+						return IPACM_FAILURE;
+					}
+					data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+				        ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+					IPACMDBG("Got a usb link_up event (Interface %s, %d) \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+
+                                        /*--------------------------------------------------------------------------
+                                           Post LAN iface (ECM) link up event
+                                         ---------------------------------------------------------------------------*/
+                                        evt_data.event = IPA_USB_LINK_UP_EVENT;
+					evt_data.evt_data = data_fid;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
+										 data_fid->if_index);
+                                }
+                                else if(!(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+                                {
+					data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+					if(data_fid == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_fid\n");
+						return IPACM_FAILURE;
+					}
+					data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+					IPACMDBG_H("Got a usb link_down event (Interface %s) \n", dev_name);
+
+					/*--------------------------------------------------------------------------
+						Post LAN iface (ECM) link down event
+					---------------------------------------------------------------------------*/
+					evt_data.event = IPA_LINK_DOWN_EVENT;
+					evt_data.evt_data = data_fid;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					IPACMDBG_H("Posting usb IPA_LINK_DOWN_EVENT with if index: %d\n",
+										 data_fid->if_index);
+                                }
+			}
+			break;
+
+		case RTM_DELLINK:
+			IPACMDBG("\n GOT dellink event\n");
+			msg_ptr->type = nlh->nlmsg_type;
+			msg_ptr->link_event = true;
+			IPACMDBG("entering rtm decode\n");
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+			{
+				IPACMERR("Failed to decode rtm link message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("Got RTM_DELLINK with below values\n");
+				IPACMDBG("RTM_DELLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+				IPACMDBG("RTM_DELLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+				IPACMDBG("RTM_DELLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+				IPACMDBG("RTM_DELLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+				/* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+				   but this should be processed in case of MDM for Ehernet interface.
+				*/
+#ifdef FEATURE_IPA_ANDROID
+				if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+				{
+					IPACMERR(" ignore this RTM_DELLINK msg \n");
+					return IPACM_SUCCESS;
+				}
+#endif
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+					return IPACM_FAILURE;
+				}
+				IPACMDBG("Interface %s bring down \n", dev_name);
+
+				/* post link down to command queue */
+				evt_data.event = IPA_LINK_DOWN_EVENT;
+				data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+				if(data_fid == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_fid\n");
+					return IPACM_FAILURE;
+				}
+
+				data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+				IPACMDBG_H("posting IPA_LINK_DOWN_EVENT with if idnex:%d\n",
+								 data_fid->if_index);
+				evt_data.evt_data = data_fid;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				/* finish command queue */
+			}
+			break;
+
+		case RTM_NEWADDR:
+			IPACMDBG("\n GOT RTM_NEWADDR event\n");
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_addr(buffer, buflen, &(msg_ptr->nl_addr_info)))
+			{
+				IPACMERR("Failed to decode rtm addr message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_addr_info.metainfo.ifa_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+				}
+				IPACMDBG("Interface %s \n", dev_name);
+
+				data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+				if(data_addr == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_addr\n");
+					return IPACM_FAILURE;
+				}
+
+				if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+				{
+					data_addr->iptype = IPA_IP_v6;
+					IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+					IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_addr_info.attr_info.prefix_addr);
+					data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+					data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+					data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+					data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+				}
+				else
+				{
+					data_addr->iptype = IPA_IP_v4;
+					IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+					IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_addr_info.attr_info.prefix_addr);
+					data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+				}
+
+				evt_data.event = IPA_ADDR_ADD_EVENT;
+				data_addr->if_index = msg_ptr->nl_addr_info.metainfo.ifa_index;
+				if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+				{
+				    IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv6 addr:0x%x:%x:%x:%x\n",
+								 data_addr->if_index,
+								 data_addr->ipv6_addr[0],
+								 data_addr->ipv6_addr[1],
+								 data_addr->ipv6_addr[2],
+								 data_addr->ipv6_addr[3]);
+                }
+				else
+				{
+				IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+								 data_addr->if_index,
+								 data_addr->ipv4_addr);
+				}
+				evt_data.evt_data = data_addr;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+			}
+			break;
+
+		case RTM_NEWROUTE:
+
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+			{
+				IPACMERR("Failed to decode rtm route message\n");
+				return IPACM_FAILURE;
+			}
+
+			IPACMDBG("In case RTM_NEWROUTE\n");
+			IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+			IPACMDBG("protocol: %d\n", msg_ptr->nl_route_info.metainfo.rtm_protocol);
+			IPACMDBG("rtm_scope: %d\n", msg_ptr->nl_route_info.metainfo.rtm_scope);
+			IPACMDBG("rtm_table: %d\n", msg_ptr->nl_route_info.metainfo.rtm_table);
+			IPACMDBG("rtm_family: %d\n", msg_ptr->nl_route_info.metainfo.rtm_family);
+			IPACMDBG("param_mask: 0x%x\n", msg_ptr->nl_route_info.attr_info.param_mask);
+
+			/* take care of route add default route & uniroute */
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+				 ((msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) ||
+				  (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_RA)) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_scope == RT_SCOPE_UNIVERSE) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT RTM_NEWROUTE event\n");
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+
+					IPACM_NL_REPORT_ADDR( "route add -host", msg_ptr->nl_route_info.attr_info.dst_addr );
+					IPACM_NL_REPORT_ADDR( "gw", msg_ptr->nl_route_info.attr_info.gateway_addr );
+					IPACMDBG("dev %s\n",dev_name );
+					/* insert to command queue */
+					IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+					temp = (-1);
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr,
+									 data_addr->ipv4_addr_mask);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+
+				}
+				else
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+
+					if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+					{
+						/* insert to command queue */
+						data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+						if(data_addr == NULL)
+						{
+							IPACMERR("unable to allocate memory for event data_addr\n");
+							return IPACM_FAILURE;
+						}
+
+						if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+						{
+							IPACMDBG_H("ip -6 route add default dev %s metric %d\n",
+											 dev_name,
+											 msg_ptr->nl_route_info.attr_info.priority);
+						}
+						else
+						{
+							IPACMDBG_H("ip -6 route add default dev %s\n", dev_name);
+						}
+
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+						data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+						data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+						data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+						data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+						data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+						data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+						data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+						data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+						data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+						data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+						IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+						evt_data.event = IPA_ROUTE_ADD_EVENT;
+						data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+						data_addr->iptype = IPA_IP_v6;
+
+						IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+										 data_addr->if_index);
+						evt_data.evt_data = data_addr;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						/* finish command queue */
+
+					}
+					else
+					{
+						IPACM_NL_REPORT_ADDR( "route add default gw \n", msg_ptr->nl_route_info.attr_info.gateway_addr );
+						IPACMDBG_H("dev %s \n", dev_name);
+						IPACM_NL_REPORT_ADDR( "dstIP:", msg_ptr->nl_route_info.attr_info.dst_addr );
+
+						/* insert to command queue */
+						data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+						if(data_addr == NULL)
+						{
+							IPACMERR("unable to allocate memory for event data_addr\n");
+							return IPACM_FAILURE;
+						}
+
+						IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+						IPACM_EVENT_COPY_ADDR_v4( if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+						IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+						evt_data.event = IPA_ROUTE_ADD_EVENT;
+						data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+						data_addr->iptype = IPA_IP_v4;
+						data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+						data_addr->ipv4_addr_gw = ntohl(if_ipv4_addr_gw);
+						data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+            IPACMDBG_H("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x, mask: 0x%x and gw: 0x%x\n",
+										 data_addr->if_index,
+										 data_addr->ipv4_addr,
+										 data_addr->ipv4_addr_mask,
+										 data_addr->ipv4_addr_gw);
+						evt_data.evt_data = data_addr;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						/* finish command queue */
+					}
+				}
+			}
+
+			/* ipv6 routing table */
+			if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT valid v6-RTM_NEWROUTE event\n");
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+					return IPACM_FAILURE;
+				}
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					IPACM_NL_REPORT_ADDR( "Route ADD DST:", msg_ptr->nl_route_info.attr_info.dst_addr );
+					IPACMDBG("%d, metric %d, dev %s\n",
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					 IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+					data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+					data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+					data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+					data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+					mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+					for(mask_index = 0; mask_index < 4; mask_index++)
+					{
+						if(mask_value_v6 >= 32)
+						{
+							mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 -= 32;
+						}
+						else
+						{
+							mask_v6(mask_value_v6, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 = 0;
+						}
+					}
+
+					IPACMDBG("ADD IPV6 MASK %d: %08x:%08x:%08x:%08x \n",
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 data_addr->ipv6_addr_mask[0],
+									 data_addr->ipv6_addr_mask[1],
+									 data_addr->ipv6_addr_mask[2],
+									 data_addr->ipv6_addr_mask[3]);
+
+					data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+					data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+					data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+					data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 addr\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+				{
+					IPACM_NL_REPORT_ADDR( "Route ADD ::/0  Next Hop:", msg_ptr->nl_route_info.attr_info.gateway_addr );
+					IPACMDBG(" metric %d, dev %s\n",
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+                    data_addr->ipv6_addr[0]=ntohl(data_addr->ipv6_addr[0]);
+                    data_addr->ipv6_addr[1]=ntohl(data_addr->ipv6_addr[1]);
+                    data_addr->ipv6_addr[2]=ntohl(data_addr->ipv6_addr[2]);
+                    data_addr->ipv6_addr[3]=ntohl(data_addr->ipv6_addr[3]);
+
+					IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+					data_addr->ipv6_addr_mask[0]=ntohl(data_addr->ipv6_addr_mask[0]);
+                    data_addr->ipv6_addr_mask[1]=ntohl(data_addr->ipv6_addr_mask[1]);
+                    data_addr->ipv6_addr_mask[2]=ntohl(data_addr->ipv6_addr_mask[2]);
+                    data_addr->ipv6_addr_mask[3]=ntohl(data_addr->ipv6_addr_mask[3]);
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+			break;
+
+		case RTM_DELROUTE:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+			{
+				IPACMERR("Failed to decode rtm route message\n");
+				return IPACM_FAILURE;
+			}
+			/* take care of route delete of default route & uniroute */
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+				 ((msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) ||
+				  (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_RA)) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_scope == 0) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+					IPACM_NL_REPORT_ADDR( "route del -host ", msg_ptr->nl_route_info.attr_info.dst_addr);
+					IPACM_NL_REPORT_ADDR( " gw ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+					IPACMDBG("dev %s\n", dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+					IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+					temp = (-1);
+					if_ipipv4_addr_mask = ntohl(temp);
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG_H("Posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr,
+									 data_addr->ipv4_addr_mask);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+				else
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+						return IPACM_FAILURE;
+					}
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+					{
+						if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+						{
+							IPACMDBG("ip -6 route del default dev %s metric %d\n",
+											 dev_name,
+											 msg_ptr->nl_route_info.attr_info.priority);
+						}
+						else
+						{
+							IPACMDBG("ip -6 route del default dev %s\n", dev_name);
+						}
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+						data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+						data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+						data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+						data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+						data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+						data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+						IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+						data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+						data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+						data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+						data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+						IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+						data_addr->iptype = IPA_IP_v6;
+					}
+					else
+					{
+						IPACM_NL_REPORT_ADDR( "route del default gw", msg_ptr->nl_route_info.attr_info.gateway_addr);
+						IPACMDBG("dev %s\n", dev_name);
+
+						IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+						IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+						data_addr->ipv4_addr_mask = ntohl(data_addr->ipv4_addr_mask);
+
+						data_addr->iptype = IPA_IP_v4;
+					}
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+
+					IPACMDBG_H("Posting IPA_ROUTE_DEL_EVENT with if index:%d\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+
+			/* ipv6 routing table */
+			if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT valid v6-RTM_DELROUTE event\n");
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name");
+					return IPACM_FAILURE;
+				}
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					IPACM_NL_REPORT_ADDR( "DEL", msg_ptr->nl_route_info.attr_info.dst_addr);
+					IPACMDBG("/%d, metric %d, dev %s\n",
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+					data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+					data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+					data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+					data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+					mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+					for(mask_index = 0; mask_index < 4; mask_index++)
+					{
+						IPACMDBG("%dst %d \n",
+										 mask_index,
+										 mask_value_v6);
+						if(mask_value_v6 >= 32)
+						{
+							mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 -= 32;
+							IPACMDBG("%dst: %08x \n",
+											 mask_index,
+											 data_addr->ipv6_addr_mask[mask_index]);
+						}
+						else
+						{
+							mask_v6(mask_value_v6, data_addr->ipv6_addr_mask);
+							mask_value_v6 = 0;
+							IPACMDBG("%dst: %08x \n",
+											 mask_index,
+											 data_addr->ipv6_addr_mask[mask_index]);
+						}
+					}
+
+					IPACMDBG("DEL IPV6 MASK 0st: %08x ",
+									 data_addr->ipv6_addr_mask[0]);
+					IPACMDBG("1st: %08x ",
+									 data_addr->ipv6_addr_mask[1]);
+					IPACMDBG("2st: %08x ",
+									 data_addr->ipv6_addr_mask[2]);
+					IPACMDBG("3st: %08x \n",
+									 data_addr->ipv6_addr_mask[3]);
+
+					data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+					data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+					data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+					data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG_H("posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+			break;
+
+		case RTM_NEWNEIGH:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+			{
+				IPACMERR("Failed to decode rtm neighbor message\n");
+				return IPACM_FAILURE;
+			}
+
+			ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+			if(ret_val != IPACM_SUCCESS)
+			{
+				IPACMERR("Error while getting interface index\n");
+				return IPACM_FAILURE;
+			}
+			else
+				{
+				IPACMDBG("\n GOT RTM_NEWNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+			}
+
+			/* insert to command queue */
+		    data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+		    if(data_all == NULL)
+			{
+		    	IPACMERR("unable to allocate memory for event data_all\n");
+						return IPACM_FAILURE;
+			}
+
+		    memset(data_all, 0, sizeof(ipacm_event_data_all));
+		    if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+		    {
+				IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+				IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+				data_all->ipv6_addr[0]=ntohl(data_all->ipv6_addr[0]);
+				data_all->ipv6_addr[1]=ntohl(data_all->ipv6_addr[1]);
+				data_all->ipv6_addr[2]=ntohl(data_all->ipv6_addr[2]);
+				data_all->ipv6_addr[3]=ntohl(data_all->ipv6_addr[3]);
+				data_all->iptype = IPA_IP_v6;
+		    }
+		    else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+		    {
+   				IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+				IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+		    	data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+		    	data_all->iptype = IPA_IP_v4;
+		    }
+		    else
+		    {
+		        data_all->iptype = IPA_IP_v6;
+		    }
+
+		    IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+
+		    memcpy(data_all->mac_addr,
+		    			 msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+		    			 sizeof(data_all->mac_addr));
+			data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+			/* Add support to replace src-mac as bridge0 mac */
+			if((msg_ptr->nl_neigh_info.metainfo.ndm_family == AF_BRIDGE) &&
+				(msg_ptr->nl_neigh_info.metainfo.ndm_state == NUD_PERMANENT))
+		    {
+				/* Posting IPA_BRIDGE_LINK_UP_EVENT event */
+				evt_data.event = IPA_BRIDGE_LINK_UP_EVENT;
+				IPACMDBG_H("posting IPA_BRIDGE_LINK_UP_EVENT (%s):index:%d \n",
+                                 dev_name,
+ 		                    data_all->if_index);
+			}
+			else
+		    {
+				/* Posting new_neigh events for all LAN/WAN clients */
+				evt_data.event = IPA_NEW_NEIGH_EVENT;
+				IPACMDBG_H("posting IPA_NEW_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+                                 dev_name,
+ 		                    data_all->if_index,
+		    				 msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+			}
+		    evt_data.evt_data = data_all;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+			break;
+
+		case RTM_DELNEIGH:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+			{
+				IPACMERR("Failed to decode rtm neighbor message\n");
+				return IPACM_FAILURE;
+			}
+
+			ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+			if(ret_val != IPACM_SUCCESS)
+			{
+				IPACMERR("Error while getting interface index\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("\n GOT RTM_DELNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+			}
+
+				/* insert to command queue */
+				data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+				if(data_all == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_all\n");
+					return IPACM_FAILURE;
+				}
+
+		    memset(data_all, 0, sizeof(ipacm_event_data_all));
+		    if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+				{
+					IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+					IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+					data_all->ipv6_addr[0] = ntohl(data_all->ipv6_addr[0]);
+					data_all->ipv6_addr[1] = ntohl(data_all->ipv6_addr[1]);
+					data_all->ipv6_addr[2] = ntohl(data_all->ipv6_addr[2]);
+					data_all->ipv6_addr[3] = ntohl(data_all->ipv6_addr[3]);
+					data_all->iptype = IPA_IP_v6;
+				}
+		    else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+				{
+					IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+					IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+					data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+					data_all->iptype = IPA_IP_v4;
+				}
+		    else
+		    {
+		        data_all->iptype = IPA_IP_v6;
+		    }
+
+		    IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+		     (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+				memcpy(data_all->mac_addr,
+							 msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+							 sizeof(data_all->mac_addr));
+		    evt_data.event = IPA_DEL_NEIGH_EVENT;
+				data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+		    IPACMDBG_H("posting IPA_DEL_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+                                 dev_name,
+ 		                    data_all->if_index,
+		    				 msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+				evt_data.evt_data = data_all;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				/* finish command queue */
+			break;
+
+		default:
+			IPACMDBG(" ignore NL event %d!!!\n ", nlh->nlmsg_type);
+			break;
+
+		}
+		nlh = NLMSG_NEXT(nlh, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+
+/*  Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd)
+{
+	struct msghdr *msghdr = NULL;
+	struct iovec *iov = NULL;
+	unsigned int msglen = 0;
+	ipa_nl_msg_t *nlmsg = NULL;
+
+	nlmsg = (ipa_nl_msg_t *)malloc(sizeof(ipa_nl_msg_t));
+	if(NULL == nlmsg)
+	{
+		IPACMERR("Failed alloc of nlmsg \n");
+		goto error;
+	}
+	else
+	{
+		if(IPACM_SUCCESS != ipa_nl_recv(fd, &msghdr, &msglen))
+		{
+			IPACMERR("Failed to receive nl message \n");
+			goto error;
+		}
+
+		if(msghdr== NULL)
+		{
+			IPACMERR(" failed to get msghdr\n");
+			goto error;
+		}
+
+		iov = msghdr->msg_iov;
+
+		memset(nlmsg, 0, sizeof(ipa_nl_msg_t));
+		if(IPACM_SUCCESS != ipa_nl_decode_nlmsg((char *)iov->iov_base, msglen, nlmsg))
+		{
+			IPACMERR("Failed to decode nl message \n");
+			goto error;
+		}
+		/* Release NetLink message buffer */
+		if(msghdr)
+		{
+			ipa_nl_release_msg(msghdr);
+		}
+		if(nlmsg)
+		{
+			free(nlmsg);
+		}
+	}
+
+	return IPACM_SUCCESS;
+
+error:
+	if(msghdr)
+	{
+		ipa_nl_release_msg(msghdr);
+	}
+	if(nlmsg)
+	{
+		free(nlmsg);
+	}
+
+	return IPACM_FAILURE;
+}
+
+/*  get ipa interface name */
+int ipa_get_if_name
+(
+	 char *if_name,
+	 int if_index
+	 )
+{
+	int fd;
+	struct ifreq ifr;
+
+	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		IPACMERR("get interface name socket create failed \n");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+	ifr.ifr_ifindex = if_index;
+	IPACMDBG("Interface index %d\n", if_index);
+
+	if(ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		IPACMERR("call_ioctl_on_dev: ioctl failed:\n");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+
+	(void)strncpy(if_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+	IPACMDBG("interface name %s\n", ifr.ifr_name);
+	close(fd);
+
+	return IPACM_SUCCESS;
+}
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+	 unsigned int nl_type,
+	 unsigned int nl_groups,
+	 ipa_nl_sk_fd_set_info_t *sk_fdset,
+	 ipa_sock_thrd_fd_read_f read_f
+	 )
+{
+	ipa_nl_sk_info_t sk_info;
+	int ret_val;
+
+	memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+	IPACMDBG_H("Entering IPA NL listener init\n");
+
+	if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+	{
+		IPACMDBG_H("IPA Open netlink socket succeeds\n");
+	}
+	else
+	{
+		IPACMERR("Netlink socket open failed\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Add NETLINK socket to the list of sockets that the listener
+					 thread should listen on. */
+
+	if(ipa_nl_addfd_map(sk_fdset, sk_info.sk_fd, read_f) != IPACM_SUCCESS)
+	{
+		IPACMERR("cannot add nl routing sock for reading\n");
+		close(sk_info.sk_fd);
+		return IPACM_FAILURE;
+	}
+
+	/* Start the socket listener thread */
+	ret_val = ipa_nl_sock_listener_start(sk_fdset);
+
+	if(ret_val != IPACM_SUCCESS)
+	{
+		IPACMERR("Failed to start NL listener\n");
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* find the newroute subnet mask */
+int find_mask(int ip_v4_last, int *mask_value)
+{
+
+	switch(ip_v4_last)
+	{
+
+	case 3:
+		*mask_value = 252;
+		return IPACM_SUCCESS;
+		break;
+
+	case 7:
+		*mask_value = 248;
+		return IPACM_SUCCESS;
+		break;
+
+	case 15:
+		*mask_value = 240;
+		return IPACM_SUCCESS;
+		break;
+
+	case 31:
+		*mask_value = 224;
+		return IPACM_SUCCESS;
+		break;
+
+	case 63:
+		*mask_value = 192;
+		return IPACM_SUCCESS;
+		break;
+
+	case 127:
+		*mask_value = 128;
+		return IPACM_SUCCESS;
+		break;
+
+	case 255:
+		*mask_value = 0;
+		return IPACM_SUCCESS;
+		break;
+
+	default:
+		return IPACM_FAILURE;
+		break;
+
+	}
+}
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask)
+{
+	switch(index)
+	{
+
+	case 0:
+		*mask = 0x00000000;
+		return IPACM_SUCCESS;
+		break;
+	case 4:
+		*mask = 0xf0000000;
+		return IPACM_SUCCESS;
+		break;
+	case 8:
+		*mask = 0xff000000;
+		return IPACM_SUCCESS;
+		break;
+	case 12:
+		*mask = 0xfff00000;
+		return IPACM_SUCCESS;
+		break;
+	case 16:
+		*mask = 0xffff0000;
+		return IPACM_SUCCESS;
+		break;
+	case 20:
+		*mask = 0xfffff000;
+		return IPACM_SUCCESS;
+		break;
+	case 24:
+		*mask = 0xffffff00;
+		return IPACM_SUCCESS;
+		break;
+	case 28:
+		*mask = 0xfffffff0;
+		return IPACM_SUCCESS;
+		break;
+	case 32:
+		*mask = 0xffffffff;
+		return IPACM_SUCCESS;
+		break;
+	default:
+		return IPACM_FAILURE;
+		break;
+
+	}
+}
+
+
diff --git a/ipacm/src/IPACM_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
new file mode 100644
index 0000000..2a2555a
--- /dev/null
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -0,0 +1,276 @@
+/*
+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_Routing.cpp
+
+	@brief
+	This file implements the IPACM routing functionality.
+
+	@Author
+
+*/
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Routing.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Routing::IPACM_Routing()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (0 == m_fd)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+IPACM_Routing::~IPACM_Routing()
+{
+	close(m_fd);
+}
+
+bool IPACM_Routing::DeviceNodeIsOpened()
+{
+	int res = fcntl(m_fd, F_GETFL);
+
+	if (m_fd > 0 && res >= 0) return true;
+	else return false;
+
+}
+
+bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
+{
+	int retval = 0, cnt=0;
+	bool isInvalid = false;
+
+	if (!DeviceNodeIsOpened())
+	{
+		IPACMERR("Device is not opened\n");
+		return false;
+	}
+
+	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
+		{
+			IPACMERR("Invalid dst pipe, Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+			isInvalid = true;
+		}
+	}
+
+	if(isInvalid)
+	{
+		return false;
+	}
+
+	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+	if (retval)
+	{
+		IPACMERR("Failed adding routing rule %p\n", ruleTable);
+		return false;
+	}
+
+	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		IPACMDBG("Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+	}
+
+	IPACMDBG_H("Added routing rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
+	if (retval)
+	{
+		IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
+		return false;
+	}
+
+	IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Routing::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval)
+	{
+		IPACMERR("Failed commiting routing rules.\n");
+		return false;
+	}
+
+	IPACMDBG_H("Commited routing rules to IPA HW.\n");
+	return true;
+}
+
+bool IPACM_Routing::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
+	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval)
+	{
+		IPACMERR("Failed resetting routing block.\n");
+		return false;
+	}
+
+	IPACMDBG_H("Reset command issued to IPA routing block.\n");
+	return true;
+}
+
+bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
+	if (retval)
+	{
+		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
+		return false;
+	}
+	IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+	/* put routing table right after successfully get routing table */
+	PutRoutingTable(routingTable->hdl);
+
+	return true;
+}
+
+bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
+	if (retval)
+	{
+		IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
+		return false;
+	}
+
+	IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
+	return true;
+}
+
+bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
+{
+	const uint8_t NUM_RULES = 1;
+	struct ipa_ioc_del_rt_rule *rt_rule;
+	struct ipa_rt_rule_del *rt_rule_entry;
+	bool res = true;
+	int len = 0;
+
+	if (rt_rule_hdl == 0)
+	{
+		IPACMERR(" No route handle passed. Ignoring it\n");
+		return res;
+	}
+
+	len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
+	rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
+	if (rt_rule == NULL)
+	{
+		IPACMERR("unable to allocate memory for del route rule\n");
+		return false;
+	}
+
+	memset(rt_rule, 0, len);
+	rt_rule->commit = 1;
+	rt_rule->num_hdls = NUM_RULES;
+	rt_rule->ip = ip;
+
+	rt_rule_entry = &rt_rule->hdl[0];
+	rt_rule_entry->status = -1;
+	rt_rule_entry->hdl = rt_rule_hdl;
+
+	IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
+	if ((false == DeleteRoutingRule(rt_rule)) ||
+			(rt_rule_entry->status))
+	{
+		PERROR("Routing rule deletion failed!\n");
+		goto fail;
+		res = false;
+	}
+
+fail:
+	free(rt_rule);
+
+	return res;
+}
+
+bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
+{
+	int retval = 0, cnt;
+
+	if (!DeviceNodeIsOpened())
+	{
+		IPACMERR("Device is not opened\n");
+		return false;
+	}
+
+	retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
+	if (retval)
+	{
+		IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
+		return false;
+	}
+
+	for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
+	{
+		if(mdfyRules->rules[cnt].status != 0)
+		{
+			IPACMERR("Unable to modify rule: %d\n", cnt);
+		}
+	}
+
+	IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
+	return true;
+}
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
new file mode 100644
index 0000000..4ee6c10
--- /dev/null
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -0,0 +1,6139 @@
+/*
+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_Wan.cpp
+
+		@brief
+		This file implements the WAN iface functionality.
+
+		@Author
+		Skylar Chang
+
+*/
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Xml.h>
+#include <IPACM_Log.h>
+#include "IPACM_EvtDispatcher.h"
+#include <IPACM_IfaceManager.h>
+#include "linux/rmnet_ipa_fd_ioctl.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+#include <IPACM_ConntrackListener.h>
+#include "linux/ipa_qmi_service_v01.h"
+
+bool IPACM_Wan::wan_up = false;
+bool IPACM_Wan::wan_up_v6 = false;
+uint8_t IPACM_Wan::xlat_mux_id = 0;
+
+uint32_t IPACM_Wan::curr_wan_ip = 0;
+int IPACM_Wan::num_v4_flt_rule = 0;
+int IPACM_Wan::num_v6_flt_rule = 0;
+
+struct ipa_flt_rule_add IPACM_Wan::flt_rule_v4[IPA_MAX_FLT_RULE];
+struct ipa_flt_rule_add IPACM_Wan::flt_rule_v6[IPA_MAX_FLT_RULE];
+
+char IPACM_Wan::wan_up_dev_name[IF_NAME_LEN];
+
+bool IPACM_Wan::backhaul_is_sta_mode = false;
+bool IPACM_Wan::is_ext_prop_set = false;
+
+int IPACM_Wan::num_ipv4_modem_pdn = 0;
+int IPACM_Wan::num_ipv6_modem_pdn = 0;
+
+bool IPACM_Wan::embms_is_on = false;
+bool IPACM_Wan::backhaul_is_wan_bridge = false;
+
+uint32_t IPACM_Wan::backhaul_ipv6_prefix[2];
+
+#ifdef FEATURE_IPA_ANDROID
+int	IPACM_Wan::ipa_if_num_tether_v4_total = 0;
+int	IPACM_Wan::ipa_if_num_tether_v6_total = 0;
+
+int	IPACM_Wan::ipa_if_num_tether_v4[IPA_MAX_IFACE_ENTRIES];
+int	IPACM_Wan::ipa_if_num_tether_v6[IPA_MAX_IFACE_ENTRIES];
+#endif
+
+IPACM_Wan::IPACM_Wan(int iface_index,
+	ipacm_wan_iface_type is_sta_mode,
+	uint8_t *mac_addr) : IPACM_Iface(iface_index)
+{
+	num_firewall_v4 = 0;
+	num_firewall_v6 = 0;
+	wan_route_rule_v4_hdl = NULL;
+	wan_route_rule_v6_hdl = NULL;
+	wan_route_rule_v6_hdl_a5 = NULL;
+	wan_client = NULL;
+
+	if(iface_query != NULL)
+	{
+		wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+		wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+		wan_route_rule_v6_hdl_a5 = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+		IPACMDBG_H("IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
+	}
+	m_is_sta_mode = is_sta_mode;
+
+	wan_v4_addr_set = false;
+	wan_v4_addr_gw_set = false;
+	wan_v6_addr_gw_set = false;
+	active_v4 = false;
+	active_v6 = false;
+	header_set_v4 = false;
+	header_set_v6 = false;
+	header_partial_default_wan_v4 = false;
+	header_partial_default_wan_v6 = false;
+	hdr_hdl_sta_v4 = 0;
+	hdr_hdl_sta_v6 = 0;
+	num_ipv6_dest_flt_rule = 0;
+	memset(ipv6_dest_flt_rule_hdl, 0, MAX_DEFAULT_v6_ROUTE_RULES*sizeof(uint32_t));
+	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+	memset(wan_v6_addr_gw, 0, sizeof(wan_v6_addr_gw));
+	ext_prop = NULL;
+	is_ipv6_frag_firewall_flt_rule_installed = false;
+	ipv6_frag_firewall_flt_rule_hdl = 0;
+
+	num_wan_client = 0;
+	header_name_count = 0;
+	memset(invalid_mac, 0, sizeof(invalid_mac));
+
+	is_xlat = false;
+	hdr_hdl_dummy_v6 = 0;
+	hdr_proc_hdl_dummy_v6 = 0;
+
+	if(iface_query != NULL)
+	{
+		wan_client_len = (sizeof(ipa_wan_client)) + (iface_query->num_tx_props * sizeof(wan_client_rt_hdl));
+		wan_client = (ipa_wan_client *)calloc(IPA_MAX_NUM_WAN_CLIENTS, wan_client_len);
+		if (wan_client == NULL)
+		{
+			IPACMERR("unable to allocate memory\n");
+			return;
+		}
+		IPACMDBG_H("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+	}
+
+
+	if(m_is_sta_mode == Q6_WAN)
+	{
+		IPACMDBG_H("The new WAN interface is modem.\n");
+		is_default_gateway = false;
+		query_ext_prop();
+	}
+	else
+	{
+		IPACMDBG_H("The new WAN interface is WLAN STA.\n");
+	}
+
+	m_fd_ipa = open(IPA_DEVICE_NAME, O_RDWR);
+	if(0 == m_fd_ipa)
+	{
+		IPACMERR("Failed to open %s\n",IPA_DEVICE_NAME);
+	}
+
+	if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
+	{
+		IPACMDBG(" IPACM->IPACM_Wan_eMBMS(%d)\n", ipa_if_num);
+		embms_is_on = true;
+		install_wan_filtering_rule(false);
+		/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+		if(tx_prop != NULL)
+		{
+			IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+			IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+        	IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+		}
+	}
+	else
+	{
+		IPACMDBG(" IPACM->IPACM_Wan(%d)\n", ipa_if_num);
+	}
+	return;
+}
+
+IPACM_Wan::~IPACM_Wan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+/* handle new_address event */
+int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_ioc_add_flt_rule *flt_rule;
+	struct ipa_flt_rule_add flt_rule_entry;
+	struct ipa_ioc_get_hdr hdr;
+
+	const int NUM_RULES = 1;
+	int num_ipv6_addr, len;
+	int res = IPACM_SUCCESS;
+
+	memset(&hdr, 0, sizeof(hdr));
+	if(tx_prop == NULL || rx_prop == NULL)
+	{
+		IPACMDBG_H("Either tx or rx property is NULL, return.\n");
+		return IPACM_SUCCESS;
+	}
+
+	/* Update the IP Type. */
+	config_ip_type(data->iptype);
+
+	if (data->iptype == IPA_IP_v6)
+	{
+		for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
+		{
+			if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+			   (ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+			   (ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+			   (ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+			{
+				IPACMDBG_H("find matched ipv6 address, index:%d \n", num_ipv6_addr);
+				return IPACM_SUCCESS;
+				break;
+			}
+		}
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+		if (!rt_rule)
+		{
+			IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = data->iptype;
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+		}
+		rt_rule_entry->at_rear = false;
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
+		ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
+		ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
+		ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = false;
+#endif
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
+
+		/* setup same rule for v6_wan table*/
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
+
+		IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, num_dft_rt_v6: %d \n",
+				dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
+				dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],num_dft_rt_v6);
+
+		/* add default filtering rules when wan-iface get global v6-prefix */
+		if (num_dft_rt_v6 == 1)
+		{
+			if(m_is_sta_mode == Q6_WAN)
+			{
+				modem_ipv6_pdn_index = num_ipv6_modem_pdn;
+				num_ipv6_modem_pdn++;
+				IPACMDBG_H("Now the number of modem ipv6 pdn is %d.\n", num_ipv6_modem_pdn);
+				init_fl_rule_ex(data->iptype);
+			}
+			else
+			{
+				init_fl_rule(data->iptype);
+			}
+		}
+
+		/* add WAN DL interface IP specific flt rule for IPv6 when backhaul is not Q6 */
+		if(m_is_sta_mode != Q6_WAN)
+		{
+			if(rx_prop != NULL && is_global_ipv6_addr(data->ipv6_addr)
+				&& num_ipv6_dest_flt_rule < MAX_DEFAULT_v6_ROUTE_RULES)
+			{
+				len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+				flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+				if (!flt_rule)
+				{
+					IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+					return IPACM_FAILURE;
+				}
+
+				flt_rule->commit = 1;
+				flt_rule->ep = rx_prop->rx[0].src_pipe;
+				flt_rule->global = false;
+				flt_rule->ip = IPA_IP_v6;
+				flt_rule->num_rules = 1;
+
+				memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+				flt_rule_entry.rule.retain_hdr = 1;
+				flt_rule_entry.rule.to_uc = 0;
+				flt_rule_entry.rule.eq_attrib_type = 0;
+				flt_rule_entry.at_rear = true;
+				flt_rule_entry.flt_rule_hdl = -1;
+				flt_rule_entry.status = -1;
+				flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+				flt_rule_entry.rule.hashable = true;
+#endif
+				memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+				flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				memcpy(flt_rule_entry.rule.attrib.u.v6.dst_addr, data->ipv6_addr, sizeof(flt_rule_entry.rule.attrib.u.v6.dst_addr));
+				flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+				flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+				flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+				flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+				memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+				if (m_filtering.AddFilteringRule(flt_rule) == false)
+				{
+					IPACMERR("Error Adding Filtering rule, aborting...\n");
+					free(flt_rule);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+					ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule] = flt_rule->rules[0].flt_rule_hdl;
+					IPACMDBG_H("IPv6 dest filter rule %d HDL:0x%x\n", num_ipv6_dest_flt_rule, ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule]);
+					num_ipv6_dest_flt_rule++;
+					free(flt_rule);
+				}
+			}
+		}
+		/* store ipv6 prefix if the ipv6 address is not link local */
+		if(is_global_ipv6_addr(data->ipv6_addr))
+		{
+			memcpy(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix));
+		}
+	    num_dft_rt_v6++;
+    }
+	else
+	{
+		if(wan_v4_addr_set)
+		{
+			/* check iface ipv4 same or not */
+			if(data->ipv4_addr == wan_v4_addr)
+			{
+				IPACMDBG_H("Already setup device (%s) ipv4 and it didn't change(0x%x)\n", dev_name, data->ipv4_addr);
+				return IPACM_SUCCESS;
+			}
+			else
+			{
+				IPACMDBG_H(" device (%s) ipv4 addr is changed\n", dev_name);
+				/* Delete default v4 RT rule */
+				IPACMDBG_H("Delete default v4 routing rules\n");
+				if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+				{
+					IPACMERR("Routing old RT rule deletion failed!\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+			}
+		}
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+							NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+		if (!rt_rule)
+		{
+			IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = data->iptype;
+		rt_rule_entry = &rt_rule->rules[0];
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		/* still need setup v4 default routing rule to A5*/
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = false;
+#endif
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
+		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
+			/* initial multicast/broadcast/fragment filter rule */
+
+		/* only do one time */
+		if(!wan_v4_addr_set)
+		{
+			/* initial multicast/broadcast/fragment filter rule */
+			if(m_is_sta_mode == Q6_WAN)
+			{
+				modem_ipv4_pdn_index = num_ipv4_modem_pdn;
+				num_ipv4_modem_pdn++;
+				IPACMDBG_H("Now the number of modem ipv4 pdn is %d.\n", num_ipv4_modem_pdn);
+				init_fl_rule_ex(data->iptype);
+			}
+			else
+			{
+				init_fl_rule(data->iptype);
+			}
+		}
+
+		wan_v4_addr = data->ipv4_addr;
+		wan_v4_addr_set = true;
+
+		if (m_is_sta_mode == Q6_WAN)
+			curr_wan_ip = data->ipv4_addr;
+
+		IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
+	}
+
+	IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
+
+fail:
+	free(rt_rule);
+
+	return res;
+}
+
+void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param)
+{
+	int ipa_interface_index;
+
+	switch (event)
+	{
+	case IPA_WLAN_LINK_DOWN_EVENT:
+		{
+			if(m_is_sta_mode == WLAN_WAN)
+			{
+				ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+				ipa_interface_index = iface_ipa_index_query(data->if_index);
+				if (ipa_interface_index == ipa_if_num)
+				{
+					IPACMDBG_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
+					handle_down_evt();
+					/* reset the STA-iface category to unknown */
+					IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
+					IPACMDBG_H("IPA_WAN_STA (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+					IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+					delete this;
+					return;
+				}
+			}
+		}
+		break;
+
+	case IPA_WAN_XLAT_CONNECT_EVENT:
+		{
+			IPACMDBG_H("Recieved IPA_WAN_XLAT_CONNECT_EVENT\n");
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+			if ((ipa_interface_index == ipa_if_num) && (m_is_sta_mode == Q6_WAN))
+			{
+				is_xlat = true;
+				IPACMDBG_H("WAN-LTE (%s) link up, iface: %d is_xlat: \n",
+						IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,data->if_index, is_xlat);
+			}
+			break;
+		}
+	case IPA_CFG_CHANGE_EVENT:
+		{
+			if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == ipa_if_cate) &&
+					(m_is_sta_mode ==ECM_WAN))
+			{
+				IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category did not change(wan_mode:%d)\n", m_is_sta_mode);
+				IPACMDBG_H("Now the cradle wan mode is %d.\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode);
+				if(is_default_gateway == true)
+				{
+					if(backhaul_is_wan_bridge == false && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+					{
+						IPACMDBG_H("Cradle wan mode switch to bridge mode.\n");
+						backhaul_is_wan_bridge = true;
+					}
+					else if(backhaul_is_wan_bridge == true && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						IPACMDBG_H("Cradle wan mode switch to router mode.\n");
+						backhaul_is_wan_bridge = false;
+					}
+					else
+					{
+						IPACMDBG_H("No cradle mode switch, return.\n");
+						return;
+					}
+					/* post wan mode change event to LAN/WLAN */
+					if(IPACM_Wan::wan_up == true)
+					{
+						IPACMDBG_H("This interface is default GW.\n");
+						ipacm_cmd_q_data evt_data;
+						memset(&evt_data, 0, sizeof(evt_data));
+
+						ipacm_event_cradle_wan_mode *data_wan_mode = NULL;
+						data_wan_mode = (ipacm_event_cradle_wan_mode *)malloc(sizeof(ipacm_event_cradle_wan_mode));
+						if(data_wan_mode == NULL)
+						{
+							IPACMERR("unable to allocate memory.\n");
+							return;
+						}
+						data_wan_mode->cradle_wan_mode = IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode;
+						evt_data.event = IPA_CRADLE_WAN_MODE_SWITCH;
+						evt_data.evt_data = data_wan_mode;
+						IPACMDBG_H("Posting IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+					}
+					/* update the firewall flt rule actions */
+					if(active_v4)
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						config_dft_firewall_rules(IPA_IP_v4);
+					}
+					if(active_v6)
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						config_dft_firewall_rules(IPA_IP_v6);
+					}
+				}
+				else
+				{
+					IPACMDBG_H("This interface is not default GW, ignore.\n");
+				}
+			}
+			else if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate) &&
+					(m_is_sta_mode ==ECM_WAN))
+			{
+				IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category changed(wan_mode:%d)\n", m_is_sta_mode);
+				/* posting link-up event for cradle use-case */
+				ipacm_cmd_q_data evt_data;
+				memset(&evt_data, 0, sizeof(evt_data));
+
+				ipacm_event_data_fid *data_fid = NULL;
+				data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+				if(data_fid == NULL)
+				{
+					IPACMERR("unable to allocate memory for IPA_USB_LINK_UP_EVENT data_fid\n");
+					return;
+				}
+				if(IPACM_Iface::ipa_get_if_index(dev_name, &(data_fid->if_index)))
+				{
+					IPACMERR("Error while getting interface index for %s device", dev_name);
+				}
+				evt_data.event = IPA_USB_LINK_UP_EVENT;
+				evt_data.evt_data = data_fid;
+				IPACMDBG_H("Posting event:%d\n", evt_data.event);
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+				/* delete previous instance */
+				handle_down_evt();
+				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+				delete this;
+				return;
+			}
+		}
+		break;
+
+	case IPA_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				if(m_is_sta_mode == Q6_WAN)
+				{
+						IPACMDBG_H("Received IPA_LINK_DOWN_EVENT\n");
+						handle_down_evt_ex();
+						IPACMDBG_H("IPA_WAN_Q6 (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+						IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+						delete this;
+						return;
+				}
+				else if (m_is_sta_mode == ECM_WAN)
+				{
+					IPACMDBG_H("Received IPA_LINK_DOWN_EVENT(wan_mode:%d)\n", m_is_sta_mode);
+					/* delete previous instance */
+					handle_down_evt();
+					IPACMDBG_H("IPA_WAN_CRADLE (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+					IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+					delete this;
+					return;
+				}
+			}
+		}
+		break;
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+					 (data->iptype == IPA_IP_v6 &&
+						data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+					  data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+			{
+				IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+				return;
+			}
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Get IPA_ADDR_ADD_EVENT: IF ip type %d, incoming ip type %d\n", ip_type, data->iptype);
+				/* check v4 not setup before, v6 can have 2 iface ip */
+				if( (data->iptype == IPA_IP_v4)
+				    || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+				{
+					IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+					handle_addr_evt(data);
+					/* checking if SW-RT_enable */
+					if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true &&
+							m_is_sta_mode != Q6_WAN)
+					{
+						/* handle software routing enable event*/
+						IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+						handle_software_routing_enable();
+					}
+
+				}
+			}
+		}
+		break;
+
+
+	case IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT:
+		{
+			ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT (Android) for ip-type (%d)\n", data->iptype);
+				/* The special below condition is to handle default gateway */
+				if ((data->iptype == IPA_IP_v4) && (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
+				{
+					if (active_v4 == false)
+					{
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+						IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d) default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
+						wan_v4_addr_gw = data->ipv4_addr_gw;
+						wan_v4_addr_gw_set = true;
+						/* Check & construct STA header */
+						handle_sta_header_add_evt();
+#else
+						IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d)\n", dev_name,data->iptype);
+#endif
+						handle_route_add_evt(data->iptype);
+					}
+#ifdef FEATURE_IPA_ANDROID
+					/* using ipa_if_index, not netdev_index */
+					post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+#endif
+				}
+				else if ((data->iptype == IPA_IP_v6) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
+				{
+					if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
+					{
+						IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
+						return;
+					}
+
+					if (active_v6 == false)
+					{
+						IPACMDBG_H("\n get default v6 route (dst:00.00.00.00) upstream\n");
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+						IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
+								data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
+						wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
+						wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
+						wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
+						wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
+						wan_v6_addr_gw_set = true;
+						/* Check & construct STA header */
+						handle_sta_header_add_evt();
+#endif
+						handle_route_add_evt(data->iptype);
+					}
+#ifdef FEATURE_IPA_ANDROID
+					/* using ipa_if_index, not netdev_index */
+					post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+#endif
+				}
+			}
+			else /* double check if current default iface is not itself */
+			{
+				if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
+				{
+					IPACMDBG_H("Received v4 IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+					wan_v4_addr_gw_set = false;
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v4);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v4);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						handle_route_del_evt(IPA_IP_v4);
+					}
+				}
+				else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
+				{
+				    IPACMDBG_H("Received v6 IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					IPACMDBG_H("need clean default v6 route for old iface (%s)\n", dev_name);
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v6);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v6);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						handle_route_del_evt(IPA_IP_v6);
+					}
+				}
+			}
+		}
+		break;
+
+	case IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT:
+		{
+			ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT\n");
+				if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
+				{
+					IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+					wan_v4_addr_gw_set = false;
+#ifdef FEATURE_IPA_ANDROID
+					/* using ipa_if_index, not netdev_index */
+					post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+					/* no any ipv4 tether iface support*/
+					if(IPACM_Wan::ipa_if_num_tether_v4_total != 0)
+					{
+						IPACMDBG_H("still have tether ipv4 client on upsteam iface\n");
+						return;
+					}
+#endif
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v4);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v4);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						handle_route_del_evt(IPA_IP_v4);
+					}
+				}
+				else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
+				{
+#ifdef FEATURE_IPA_ANDROID
+					/* using ipa_if_index, not netdev_index */
+					post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+					/* no any ipv6 tether iface support*/
+					if(IPACM_Wan::ipa_if_num_tether_v6_total != 0)
+					{
+						IPACMDBG_H("still have tether ipv6 client on upsteam iface\n");
+						return;
+					}
+#endif
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v6);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v6);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						handle_route_del_evt(IPA_IP_v6);
+					}
+				}
+			}
+		}
+		break;
+	case IPA_NETWORK_STATS_UPDATE_EVENT:
+		{
+			ipa_get_apn_data_stats_resp_msg_v01 *data = (ipa_get_apn_data_stats_resp_msg_v01 *)param;
+			if (!data->apn_data_stats_list_valid)
+			{
+				IPACMERR("not valid APN\n");
+				return;
+			}
+			else
+			{
+				handle_network_stats_update(data);
+			}
+		}
+		break;
+	case IPA_ROUTE_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_ROUTE_ADD_EVENT\n");
+				IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
+				IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+
+				/* The special below condition is to handle default gateway */
+				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == false)
+					&& (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
+				{
+					wan_v4_addr_gw = data->ipv4_addr_gw;
+					wan_v4_addr_gw_set = true;
+					IPACMDBG_H("adding routing table, dev (%s) ip-type(%d), default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
+					/* Check & construct STA header */
+					handle_sta_header_add_evt();
+					handle_route_add_evt(data->iptype);
+					/* Add IPv6 routing table if XLAT is enabled */
+					if(is_xlat && (m_is_sta_mode == Q6_WAN) && (active_v6 == false))
+					{
+						IPACMDBG_H("XLAT enabled: adding IPv6 routing table dev (%s)\n", dev_name);
+						handle_route_add_evt(IPA_IP_v6);
+					}
+				}
+				else if ((data->iptype == IPA_IP_v6) &&
+						(!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) &&
+						(active_v6 == false) &&	(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
+				{
+					if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
+					{
+						IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
+						return;
+					}
+
+					IPACMDBG_H("\n get default v6 route (dst:00.00.00.00)\n");
+					IPACMDBG_H(" IPV6 dst: %08x:%08x:%08x:%08x \n",
+							data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+					IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
+							data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
+					wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
+					wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
+					wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
+					wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
+					wan_v6_addr_gw_set = true;
+					/* Check & construct STA header */
+					handle_sta_header_add_evt();
+					handle_route_add_evt(data->iptype);
+				}
+			}
+			else /* double check if current default iface is not itself */
+			{
+				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
+				{
+					IPACMDBG_H("Received v4 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
+					IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+					IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+					wan_v4_addr_gw_set = false;
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v4);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v4);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						handle_route_del_evt(IPA_IP_v4);
+					}
+				}
+				else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == true))
+				{
+				    IPACMDBG_H("Received v6 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+					IPACMDBG_H("need clean default v6 route for old iface (%s)\n", dev_name);
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v6);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v6);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						handle_route_del_evt(IPA_IP_v6);
+					}
+				}
+			}
+		}
+		break;
+
+	case IPA_ROUTE_DEL_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_ROUTE_DEL_EVENT\n");
+				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
+				{
+					IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+					wan_v4_addr_gw_set = false;
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v4);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v4);
+
+						if(is_xlat && active_v6 == true)
+						{
+							IPACMDBG_H("XLAT enabled: Delete IPv6 routing table dev (%s)\n", dev_name);
+							del_wan_firewall_rule(IPA_IP_v6);
+							install_wan_filtering_rule(false);
+							handle_route_del_evt_ex(IPA_IP_v6);
+						}
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						handle_route_del_evt(IPA_IP_v4);
+					}
+				}
+				else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == true))
+				{
+
+					IPACMDBG_H("get del default v6 route (dst:00.00.00.00)\n");
+					if(m_is_sta_mode == Q6_WAN)
+					{
+						del_wan_firewall_rule(IPA_IP_v6);
+						install_wan_filtering_rule(false);
+						handle_route_del_evt_ex(IPA_IP_v6);
+					}
+					else
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						handle_route_del_evt(IPA_IP_v6);
+					}
+				}
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+
+				if (m_is_sta_mode == WLAN_WAN)
+				{
+					if (data->iptype == IPA_IP_v4 && data->ipv4_addr == wan_v4_addr)
+					{
+						IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+						IPACMDBG_H("for its own ipv4 address\n");
+						return;
+					}
+					else if (data->iptype == IPA_IP_v6)
+					{
+						for (int num_ipv6_addr = 0; num_ipv6_addr < num_dft_rt_v6; num_ipv6_addr++)
+						{
+							if ((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+								(ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+								(ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+								(ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+							{
+								IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+								IPACMDBG_H("for its own ipv6 address\n");
+								return;
+							}
+						}
+					}
+				}
+
+				IPACMDBG_H("wan-iface got client \n");
+				/* first construc WAN-client full header */
+				if(memcmp(data->mac_addr,
+						invalid_mac,
+						sizeof(data->mac_addr)) == 0)
+				{
+					IPACMDBG_H("Received invalid Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 data->mac_addr[0], data->mac_addr[1], data->mac_addr[2],
+					 data->mac_addr[3], data->mac_addr[4], data->mac_addr[5]);
+					return;
+				}
+
+				handle_wan_hdr_init(data->mac_addr);
+				IPACMDBG_H("construct wan-client header and route rules \n");
+				/* Associate with IP and construct RT-rule */
+				if (handle_wan_client_ipaddr(data) == IPACM_FAILURE)
+				{
+					return;
+				}
+				handle_wan_client_route_rule(data->mac_addr, data->iptype);
+				/* Check & construct STA header */
+				handle_sta_header_add_evt();
+				return;
+			}
+		}
+		break;
+
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+		/* handle software routing enable event */
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			install_wan_filtering_rule(true);
+		}
+		else
+		{
+			handle_software_routing_enable();
+		}
+		break;
+
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+		/* handle software routing disable event */
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			/* send current DL rules to modem */
+			install_wan_filtering_rule(false);
+			softwarerouting_act = false;
+		}
+		else
+		{
+			handle_software_routing_disable();
+		}
+		break;
+
+	case IPA_FIREWALL_CHANGE_EVENT:
+		IPACMDBG_H("Received IPA_FIREWALL_CHANGE_EVENT\n");
+
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			if(is_default_gateway == false)
+			{
+				IPACMDBG_H("Interface %s is not default gw, return.\n", dev_name);
+				return;
+			}
+
+			if(ip_type == IPA_IP_v4)
+			{
+				del_wan_firewall_rule(IPA_IP_v4);
+				config_wan_firewall_rule(IPA_IP_v4);
+				install_wan_filtering_rule(false);
+			}
+			else if(ip_type == IPA_IP_v6)
+			{
+				del_wan_firewall_rule(IPA_IP_v6);
+				config_wan_firewall_rule(IPA_IP_v6);
+				install_wan_filtering_rule(false);
+			}
+			else if(ip_type == IPA_IP_MAX)
+			{
+				del_wan_firewall_rule(IPA_IP_v4);
+				config_wan_firewall_rule(IPA_IP_v4);
+
+				del_wan_firewall_rule(IPA_IP_v6);
+				config_wan_firewall_rule(IPA_IP_v6);
+				install_wan_filtering_rule(false);
+			}
+			else
+			{
+				IPACMERR("IP type is not expected.\n");
+			}
+		}
+		else
+		{
+			if (active_v4)
+			{
+				del_dft_firewall_rules(IPA_IP_v4);
+				config_dft_firewall_rules(IPA_IP_v4);
+			}
+			if (active_v6)
+			{
+
+				del_dft_firewall_rules(IPA_IP_v6);
+				config_dft_firewall_rules(IPA_IP_v6);
+			}
+		}
+		break;
+
+		case IPA_WLAN_SWITCH_TO_SCC:
+			if(IPACM_Wan::backhaul_is_sta_mode == true)
+			{
+				IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+				if(ip_type == IPA_IP_MAX)
+				{
+					handle_wlan_SCC_MCC_switch(true, IPA_IP_v4);
+					handle_wlan_SCC_MCC_switch(true, IPA_IP_v6);
+					handle_wan_client_SCC_MCC_switch(true, IPA_IP_v4);
+					handle_wan_client_SCC_MCC_switch(true, IPA_IP_v6);
+				}
+				else
+				{
+					handle_wlan_SCC_MCC_switch(true, ip_type);
+					handle_wan_client_SCC_MCC_switch(true, ip_type);
+				}
+			}
+			break;
+
+		case IPA_WLAN_SWITCH_TO_MCC:
+			if(IPACM_Wan::backhaul_is_sta_mode == true)
+			{
+				IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+				if(ip_type == IPA_IP_MAX)
+				{
+					handle_wlan_SCC_MCC_switch(false, IPA_IP_v4);
+					handle_wlan_SCC_MCC_switch(false, IPA_IP_v6);
+					handle_wan_client_SCC_MCC_switch(false, IPA_IP_v4);
+					handle_wan_client_SCC_MCC_switch(false, IPA_IP_v6);
+				}
+				else
+				{
+					handle_wlan_SCC_MCC_switch(false, ip_type);
+					handle_wan_client_SCC_MCC_switch(false, ip_type);
+				}
+			}
+			break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::handle_route_add_evt(ipa_ip_type iptype)
+{
+
+	/* add default WAN route */
+	struct ipa_ioc_add_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_ioc_get_hdr sRetHeader;
+	uint32_t cnt, tx_index = 0;
+	const int NUM = 1;
+	ipacm_cmd_q_data evt_data;
+	struct ipa_ioc_copy_hdr sCopyHeader; /* checking if partial header*/
+	struct ipa_ioc_get_hdr hdr;
+
+	IPACMDBG_H("ip-type:%d\n", iptype);
+
+	/* copy header from tx-property, see if partial or not */
+	/* assume all tx-property uses the same header name for v4 or v6*/
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties, ignore default route setting\n");
+		return IPACM_SUCCESS;
+	}
+
+	is_default_gateway = true;
+	IPACMDBG_H("Default route is added to iface %s.\n", dev_name);
+
+	if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+	{
+		IPACM_Wan::backhaul_is_wan_bridge = true;
+	}
+	else
+	{
+		IPACM_Wan::backhaul_is_wan_bridge = false;
+	}
+	IPACMDBG_H("backhaul_is_wan_bridge ?: %d \n", IPACM_Wan::backhaul_is_wan_bridge);
+
+	if (m_is_sta_mode !=Q6_WAN)
+	{
+		IPACM_Wan::backhaul_is_sta_mode	= true;
+		if((iptype==IPA_IP_v4) && (header_set_v4 != true))
+		{
+			header_partial_default_wan_v4 = true;
+			IPACMDBG_H("STA ipv4-header haven't constructed \n");
+			return IPACM_SUCCESS;
+		}
+		else if((iptype==IPA_IP_v6) && (header_set_v6 != true))
+		{
+			header_partial_default_wan_v6 = true;
+			IPACMDBG_H("STA ipv6-header haven't constructed \n");
+			return IPACM_SUCCESS;
+		}
+	}
+	else
+	{
+		IPACM_Wan::backhaul_is_sta_mode	= false;
+		IPACMDBG_H("reset backhaul to LTE \n");
+
+		if (iface_query != NULL && iface_query->num_ext_props > 0)
+		{
+			if(ext_prop == NULL)
+			{
+				IPACMERR("Extended property is empty.\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->SetQmapId(ext_prop->ext[0].mux_id);
+				IPACMDBG_H("Setting up QMAP ID %d.\n", ext_prop->ext[0].mux_id);
+			}
+		}
+		else
+		{
+			IPACMERR("iface_query is empty.\n");
+			return IPACM_FAILURE;
+		}
+	}
+#if 0
+    for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+	{
+		if(tx_prop->tx[cnt].ip==iptype)
+		break;
+	}
+
+	if(tx_prop->tx[cnt].hdr_name != NULL)
+	{
+	    memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+	    memcpy(sCopyHeader.name,
+	    			 tx_prop->tx[cnt].hdr_name,
+	    			 sizeof(sCopyHeader.name));
+
+	    IPACMDBG_H("header name: %s\n", sCopyHeader.name);
+	    if (m_header.CopyHeader(&sCopyHeader) == false)
+	    {
+	    	IPACMERR("ioctl copy header failed");
+	    	return IPACM_FAILURE;
+	    }
+	    IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+	    if(sCopyHeader.is_partial)
+	    {
+ 	        IPACMDBG_H("Not setup default WAN routing rules cuz the header is not complete\n");
+            if(iptype==IPA_IP_v4)
+			{
+				header_partial_default_wan_v4 = true;
+            }
+			else
+			{
+				header_partial_default_wan_v6 = true;
+			}
+			return IPACM_SUCCESS;
+	    }
+	    else
+	    {
+            if(iptype==IPA_IP_v4)
+			{
+				header_partial_default_wan_v4 = false;
+            }
+			else
+			{
+				header_partial_default_wan_v6 = false;
+			}
+	    }
+    }
+#endif
+
+	rt_rule = (struct ipa_ioc_add_rt_rule *)
+		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_add));
+
+	if (!rt_rule)
+	{
+		IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = (uint8_t)NUM;
+	rt_rule->ip = iptype;
+
+
+	IPACMDBG_H(" WAN table created %s \n", rt_rule->rt_tbl_name);
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = true;
+
+	if(m_is_sta_mode != Q6_WAN)
+	{
+		IPACMDBG_H(" WAN instance is in STA mode \n");
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if(iptype != tx_prop->tx[tx_index].ip)
+			{
+				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+									tx_index, tx_prop->tx[tx_index].ip,iptype);
+				continue;
+			}
+
+			/* use the STA-header handler */
+			if (iptype == IPA_IP_v4)
+			{
+				strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name, sizeof(rt_rule->rt_tbl_name));
+				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
+			}
+			else
+			{
+				strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
+			}
+
+			if(IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+			{
+				IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[tx_index].alt_dst_pipe);
+				rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+			}
+			else
+			{
+				rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			}
+			memcpy(&rt_rule_entry->rule.attrib,
+						 &tx_prop->tx[tx_index].attrib,
+						 sizeof(rt_rule_entry->rule.attrib));
+
+			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			if (iptype == IPA_IP_v4)
+			{
+				rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+#ifdef FEATURE_IPA_V3
+
+				rt_rule_entry->rule.hashable = true;
+#endif
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+		    		IPACMERR("Routing rule addition failed!\n");
+		    		free(rt_rule);
+		    		return IPACM_FAILURE;
+				}
+				wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+				IPACMDBG_H("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+							 wan_route_rule_v4_hdl[tx_index],
+							 tx_index,
+							 iptype);
+			}
+			else
+			{
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+				rt_rule_entry->rule.hashable = true;
+#endif
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+		    		IPACMERR("Routing rule addition failed!\n");
+		    		free(rt_rule);
+		    		return IPACM_FAILURE;
+				}
+				wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+				IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_lan_table:0x%x,tx:%d,ip-type: %d \n",
+							 wan_route_rule_v6_hdl[tx_index],
+							 tx_index,
+							 iptype);
+			}
+		}
+	}
+
+	/* add a catch-all rule in wan dl routing table */
+
+	if (iptype == IPA_IP_v6)
+	{
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+		memset(rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add));
+		rt_rule_entry->at_rear = true;
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			memset(&hdr, 0, sizeof(hdr));
+			strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			/* create dummy ethernet header for v6 RX path */
+			IPACMDBG_H("Construct dummy ethernet_header\n");
+			if (add_dummy_rx_hdr())
+			{
+				IPACMERR("Construct dummy ethernet_header failed!\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_proc_ctx_hdl = hdr_proc_hdl_dummy_v6;
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = true;
+#endif
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+		wan_route_rule_v6_hdl_a5[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_wan_table:0x%x,tx:%d,ip-type: %d \n",
+				wan_route_rule_v6_hdl_a5[0], 0, iptype);
+	}
+
+	ipacm_event_iface_up *wanup_data;
+	wanup_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+	if (wanup_data == NULL)
+	{
+		IPACMERR("Unable to allocate memory\n");
+		free(rt_rule);
+		return IPACM_FAILURE;
+	}
+	memset(wanup_data, 0, sizeof(ipacm_event_iface_up));
+
+	if (iptype == IPA_IP_v4)
+	{
+		IPACM_Wan::wan_up = true;
+		active_v4 = true;
+		memcpy(IPACM_Wan::wan_up_dev_name,
+			dev_name,
+				sizeof(IPACM_Wan::wan_up_dev_name));
+
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			config_wan_firewall_rule(IPA_IP_v4);
+			install_wan_filtering_rule(false);
+		}
+		else
+		{
+			config_dft_firewall_rules(IPA_IP_v4);
+		}
+
+		memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+		wanup_data->ipv4_addr = wan_v4_addr;
+		if (m_is_sta_mode!=Q6_WAN)
+		{
+			wanup_data->is_sta = true;
+		}
+		else
+		{
+			wanup_data->is_sta = false;
+		}
+		IPACMDBG_H("Posting IPA_HANDLE_WAN_UP with below information:\n");
+		IPACMDBG_H("if_name:%s, ipv4_address:0x%x, is sta mode:%d\n",
+				wanup_data->ifname, wanup_data->ipv4_addr, wanup_data->is_sta);
+		memset(&evt_data, 0, sizeof(evt_data));
+
+		/* send xlat configuration for installing uplink rules */
+		if(is_xlat && (m_is_sta_mode == Q6_WAN))
+		{
+			IPACM_Wan::xlat_mux_id = ext_prop->ext[0].mux_id;
+			wanup_data->xlat_mux_id = IPACM_Wan::xlat_mux_id;
+			IPACMDBG_H("Set xlat configuraiton with below information:\n");
+			IPACMDBG_H("xlat_enabled:  xlat_mux_id: %d \n",
+					is_xlat, xlat_mux_id);
+		}
+		else
+		{
+			IPACM_Wan::xlat_mux_id = 0;
+			wanup_data->xlat_mux_id = 0;
+			IPACMDBG_H("No xlat configuratio:\n");
+		}
+		evt_data.event = IPA_HANDLE_WAN_UP;
+		evt_data.evt_data = (void *)wanup_data;
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+	}
+	else
+	{
+		memcpy(backhaul_ipv6_prefix, ipv6_prefix, sizeof(backhaul_ipv6_prefix));
+		IPACMDBG_H("Setup backhaul ipv6 prefix to be 0x%08x%08x.\n", backhaul_ipv6_prefix[0], backhaul_ipv6_prefix[1]);
+
+		IPACM_Wan::wan_up_v6 = true;
+		active_v6 = true;
+		memcpy(IPACM_Wan::wan_up_dev_name,
+			dev_name,
+				sizeof(IPACM_Wan::wan_up_dev_name));
+
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			config_wan_firewall_rule(IPA_IP_v6);
+			install_wan_filtering_rule(false);
+		}
+		else
+		{
+			config_dft_firewall_rules(IPA_IP_v6);
+		}
+
+		memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+		if (m_is_sta_mode!=Q6_WAN)
+		{
+			wanup_data->is_sta = true;
+		}
+		else
+		{
+			wanup_data->is_sta = false;
+		}
+		memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
+		IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_V6 with below information:\n");
+		IPACMDBG_H("if_name:%s, is sta mode: %d\n", wanup_data->ifname, wanup_data->is_sta);
+		IPACMDBG_H("ipv6 prefix: 0x%08x%08x.\n", ipv6_prefix[0], ipv6_prefix[1]);
+		memset(&evt_data, 0, sizeof(evt_data));
+		evt_data.event = IPA_HANDLE_WAN_UP_V6;
+		evt_data.evt_data = (void *)wanup_data;
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+	}
+
+	/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+	IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+	IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+	IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+
+	if(rt_rule != NULL)
+	{
+		free(rt_rule);
+	}
+	return IPACM_SUCCESS;
+}
+
+#ifdef FEATURE_IPA_ANDROID
+/* wan default route/filter rule configuration */
+int IPACM_Wan::post_wan_up_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
+{
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_iface_up_tehter *wanup_data;
+
+	wanup_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
+	if (wanup_data == NULL)
+	{
+		IPACMERR("Unable to allocate memory\n");
+		return IPACM_FAILURE;
+	}
+	memset(wanup_data, 0, sizeof(ipacm_event_iface_up_tehter));
+
+	wanup_data->if_index_tether = ipa_if_num_tether;
+	if (m_is_sta_mode!=Q6_WAN)
+	{
+		wanup_data->is_sta = true;
+	}
+	else
+	{
+		wanup_data->is_sta = false;
+	}
+	IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_TETHER with below information:\n");
+	IPACMDBG_H("tether_if_name:%s, is sta mode:%d\n",
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wanup_data->is_sta);
+	memset(&evt_data, 0, sizeof(evt_data));
+
+	if (iptype == IPA_IP_v4)
+	{
+		evt_data.event = IPA_HANDLE_WAN_UP_TETHER;
+		/* Add support tether ifaces to its array*/
+		IPACM_Wan::ipa_if_num_tether_v4[IPACM_Wan::ipa_if_num_tether_v4_total] = ipa_if_num_tether;
+		IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v4_total(%d) on wan_iface(%s)\n",
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
+			IPACM_Wan::ipa_if_num_tether_v4_total,
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+		IPACM_Wan::ipa_if_num_tether_v4_total++;
+	}
+	else
+	{
+		evt_data.event = IPA_HANDLE_WAN_UP_V6_TETHER;
+		memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
+		/* Add support tether ifaces to its array*/
+		IPACM_Wan::ipa_if_num_tether_v6[IPACM_Wan::ipa_if_num_tether_v6_total] = ipa_if_num_tether;
+		IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v6_total(%d) on wan_iface(%s)\n",
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
+			IPACM_Wan::ipa_if_num_tether_v6_total,
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+		IPACM_Wan::ipa_if_num_tether_v6_total++;
+	}
+		evt_data.evt_data = (void *)wanup_data;
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+	return IPACM_SUCCESS;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::post_wan_down_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
+{
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_iface_up_tehter *wandown_data;
+	int i, j;
+
+	wandown_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
+	if (wandown_data == NULL)
+	{
+		IPACMERR("Unable to allocate memory\n");
+		return IPACM_FAILURE;
+	}
+	memset(wandown_data, 0, sizeof(ipacm_event_iface_up_tehter));
+
+	wandown_data->if_index_tether = ipa_if_num_tether;
+	if (m_is_sta_mode!=Q6_WAN)
+	{
+		wandown_data->is_sta = true;
+	}
+	else
+	{
+		wandown_data->is_sta = false;
+	}
+	IPACMDBG_H("Posting IPA_HANDLE_WAN_DOWN_TETHER with below information:\n");
+	IPACMDBG_H("tether_if_name:%s, is sta mode:%d\n",
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wandown_data->is_sta);
+	memset(&evt_data, 0, sizeof(evt_data));
+
+	if (iptype == IPA_IP_v4)
+	{
+		evt_data.event = IPA_HANDLE_WAN_DOWN_TETHER;
+		/* delete support tether ifaces to its array*/
+		for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+		{
+			if(IPACM_Wan::ipa_if_num_tether_v4[i] == ipa_if_num_tether)
+			{
+				IPACMDBG_H("Found tether client at position %d name(%s)\n", i,
+				IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+				break;
+			}
+		}
+		if(i == IPACM_Wan::ipa_if_num_tether_v4_total)
+		{
+			IPACMDBG_H("Not finding the tether client.\n");
+			free(wandown_data);
+			return IPACM_SUCCESS;
+		}
+		for(j = i+1; j < IPACM_Wan::ipa_if_num_tether_v4_total; j++)
+		{
+			IPACM_Wan::ipa_if_num_tether_v4[j-1] = IPACM_Wan::ipa_if_num_tether_v4[j];
+		}
+		IPACM_Wan::ipa_if_num_tether_v4_total--;
+		IPACMDBG_H("Now the total num of ipa_if_num_tether_v4_total is %d on wan-iface(%s)\n",
+			IPACM_Wan::ipa_if_num_tether_v4_total,
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+	}
+	else
+	{
+		evt_data.event = IPA_HANDLE_WAN_DOWN_V6_TETHER;
+		/* delete support tether ifaces to its array*/
+		for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+		{
+			if(IPACM_Wan::ipa_if_num_tether_v6[i] == ipa_if_num_tether)
+			{
+				IPACMDBG_H("Found tether client at position %d name(%s)\n", i,
+				IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+				break;
+			}
+		}
+		if(i == IPACM_Wan::ipa_if_num_tether_v6_total)
+		{
+			IPACMDBG_H("Not finding the tether client.\n");
+			free(wandown_data);
+			return IPACM_SUCCESS;
+		}
+		for(j = i+1; j < IPACM_Wan::ipa_if_num_tether_v6_total; j++)
+		{
+			IPACM_Wan::ipa_if_num_tether_v6[j-1] = IPACM_Wan::ipa_if_num_tether_v6[j];
+		}
+		IPACM_Wan::ipa_if_num_tether_v6_total--;
+		IPACMDBG_H("Now the total num of ipa_if_num_tether_v6_total is %d on wan-iface(%s)\n",
+			IPACM_Wan::ipa_if_num_tether_v6_total,
+			IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+	}
+		evt_data.evt_data = (void *)wandown_data;
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+	return IPACM_SUCCESS;
+}
+#endif
+
+/* construct complete ethernet header */
+int IPACM_Wan::handle_sta_header_add_evt()
+{
+	int res = IPACM_SUCCESS, index = IPACM_INVALID_INDEX;
+	if((header_set_v4 == true) || (header_set_v6 == true))
+	{
+		IPACMDBG_H("Already add STA full header\n");
+		return IPACM_SUCCESS;
+	}
+
+	/* checking if the ipv4 same as default route */
+	if(wan_v4_addr_gw_set)
+	{
+		index = get_wan_client_index_ipv4(wan_v4_addr_gw);
+		if (index != IPACM_INVALID_INDEX)
+		{
+			IPACMDBG_H("Matched client index: %d\n", index);
+			IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(wan_client, index)->mac[0],
+					 get_client_memptr(wan_client, index)->mac[1],
+					 get_client_memptr(wan_client, index)->mac[2],
+					 get_client_memptr(wan_client, index)->mac[3],
+					 get_client_memptr(wan_client, index)->mac[4],
+					 get_client_memptr(wan_client, index)->mac[5]);
+
+			if(get_client_memptr(wan_client, index)->ipv4_header_set)
+			{
+				hdr_hdl_sta_v4 = get_client_memptr(wan_client, index)->hdr_hdl_v4;
+				header_set_v4 = true;
+				IPACMDBG_H("add full ipv4 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v4);
+				/* store external_ap's MAC */
+				memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
+			}
+			else
+			{
+				IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
+				return IPACM_FAILURE;
+			}
+
+			if(get_client_memptr(wan_client, index)->ipv6_header_set)
+			{
+				hdr_hdl_sta_v6 = get_client_memptr(wan_client, index)->hdr_hdl_v6;
+				header_set_v6 = true;
+				IPACMDBG_H("add full ipv6 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v6);
+			}
+			else
+			{
+				IPACMERR(" wan-client got ipv6 however didn't construct complete ipv6 header \n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG_H(" currently can't find matched wan-client's MAC-addr, waiting for header construction\n");
+			return IPACM_SUCCESS;
+		}
+	}
+
+	/* checking if the ipv4 same as default route */
+	if(wan_v6_addr_gw_set)
+	{
+		index = get_wan_client_index_ipv6(wan_v6_addr_gw);
+		if (index != IPACM_INVALID_INDEX)
+		{
+			IPACMDBG_H("Matched client index: %d\n", index);
+			IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(wan_client, index)->mac[0],
+					 get_client_memptr(wan_client, index)->mac[1],
+					 get_client_memptr(wan_client, index)->mac[2],
+					 get_client_memptr(wan_client, index)->mac[3],
+					 get_client_memptr(wan_client, index)->mac[4],
+					 get_client_memptr(wan_client, index)->mac[5]);
+
+			if(get_client_memptr(wan_client, index)->ipv6_header_set)
+			{
+				hdr_hdl_sta_v6 = get_client_memptr(wan_client, index)->hdr_hdl_v6;
+				header_set_v6 = true;
+				IPACMDBG_H("add full ipv6 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v6);
+				/* store external_ap's MAC */
+				memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
+			}
+			else
+			{
+				IPACMERR(" wan-client got ipv6 however didn't construct complete ipv4 header \n");
+				return IPACM_FAILURE;
+			}
+
+			if(get_client_memptr(wan_client, index)->ipv4_header_set)
+			{
+				hdr_hdl_sta_v4 = get_client_memptr(wan_client, index)->hdr_hdl_v4;
+				header_set_v4 = true;
+				IPACMDBG_H("add full ipv4 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v4);
+			}
+			else
+			{
+				IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG_H(" currently can't find matched wan-client's MAC-addr, waiting for header construction\n");
+			return IPACM_SUCCESS;
+		}
+	}
+
+	/* see if default routes are setup before constructing full header */
+	if(header_partial_default_wan_v4 == true)
+	{
+	   handle_route_add_evt(IPA_IP_v4);
+	}
+
+	if(header_partial_default_wan_v6 == true)
+	{
+	   handle_route_add_evt(IPA_IP_v6);
+	}
+	return res;
+}
+
+/* For checking attribute mask field in firewall rules for IPv6 only */
+bool IPACM_Wan::check_dft_firewall_rules_attr_mask(IPACM_firewall_conf_t *firewall_config)
+{
+	uint32_t attrib_mask = 0ul;
+	attrib_mask =	IPA_FLT_SRC_PORT_RANGE |
+			IPA_FLT_DST_PORT_RANGE |
+			IPA_FLT_TYPE |
+			IPA_FLT_CODE |
+			IPA_FLT_SPI |
+			IPA_FLT_SRC_PORT |
+			IPA_FLT_DST_PORT;
+
+	for (int i = 0; i < firewall_config->num_extd_firewall_entries; i++)
+	{
+		if (firewall_config->extd_firewall_entries[i].ip_vsn == 6)
+		{
+			if (firewall_config->extd_firewall_entries[i].attrib.attrib_mask & attrib_mask)
+			{
+				IPACMDBG_H("IHL based attribute mask is found: install IPv6 frag firewall rule \n");
+				return true;
+			}
+		}
+	}
+	IPACMDBG_H("IHL based attribute mask is not found: no IPv6 frag firewall rule \n");
+	return false;
+}
+
+/* for STA mode: add firewall rules */
+int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i, rule_v4 = 0, rule_v6 = 0, len;
+
+	IPACMDBG_H("ip-family: %d; \n", iptype);
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	/* default firewall is disable and the rule action is drop */
+	memset(&firewall_config, 0, sizeof(firewall_config));
+	strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+	IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+	if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+	{
+		IPACMDBG_H("QCMAP Firewall XML read OK \n");
+		/* find the number of v4/v6 firewall rules */
+		for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+		{
+			if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+			{
+				rule_v4++;
+			}
+			else
+			{
+				rule_v6++;
+			}
+		}
+		IPACMDBG_H("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
+	}
+	else
+	{
+		IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
+	}
+
+	/* construct ipa_ioc_add_flt_rule with N firewall rules */
+	ipa_ioc_add_flt_rule *m_pFilteringTable = NULL;
+	len = sizeof(struct ipa_ioc_add_flt_rule) + 1 * sizeof(struct ipa_flt_rule_add);
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+	if (!m_pFilteringTable)
+	{
+		IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	if(iptype == IPA_IP_v6 &&
+			firewall_config.firewall_enable == true &&
+			check_dft_firewall_rules_attr_mask(&firewall_config))
+	{
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v6;
+		m_pFilteringTable->num_rules = (uint8_t)1;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+		flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = false;
+#endif
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(struct ipa_rule_attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+			ipv6_frag_firewall_flt_rule_hdl = m_pFilteringTable->rules[0].flt_rule_hdl;
+			is_ipv6_frag_firewall_flt_rule_installed = true;
+			IPACMDBG_H("Installed IPv6 frag firewall rule, handle %d.\n", ipv6_frag_firewall_flt_rule_hdl);
+		}
+	}
+
+	if (iptype == IPA_IP_v4)
+	{
+		if (rule_v4 == 0)
+		{
+			memset(m_pFilteringTable, 0, len);
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v4;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+
+			/* firewall disable, all traffic are allowed */
+			if(firewall_config.firewall_enable == true)
+			{
+				flt_rule_entry.at_rear = true;
+
+				/* default action for v4 is go DST_NAT unless user set to exception*/
+				if(firewall_config.rule_action_accept == true)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+				}
+				else
+				{
+					if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					}
+					else
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+					}
+				}
+			}
+			else
+			{
+				flt_rule_entry.at_rear = true;
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+				}
+				else
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+				}
+            }
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.rule.hashable = true;
+#endif
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		else
+		{
+			memset(m_pFilteringTable, 0, len);
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v4;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			IPACMDBG_H("Retreiving Routing handle for routing table name:%s\n",
+							 IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+			{
+				IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			IPACMDBG_H("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
+
+            if(firewall_config.firewall_enable == true)
+            {
+			rule_v4 = 0;
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		    			flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+					flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+
+					/* Accept v4 matched rules*/
+                    if(firewall_config.rule_action_accept == true)
+			        {
+						if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+						{
+							flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+						}
+						else
+						{
+							flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+						}
+			        }
+			        else
+			        {
+			            flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+                    }
+#ifdef FEATURE_IPA_V3
+					flt_rule_entry.rule.hashable = true;
+#endif
+					memcpy(&flt_rule_entry.rule.attrib,
+								 &firewall_config.extd_firewall_entries[i].attrib,
+								 sizeof(struct ipa_rule_attrib));
+
+					IPACMDBG_H("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					/* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
+							== IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+							/* save v4 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+							/* save v4 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+					}
+					else
+					{
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+							/* save v4 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+					}
+				}
+			} /* end of firewall ipv4 filter rule add for loop*/
+            }
+			/* configure default filter rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+
+			/* firewall disable, all traffic are allowed */
+            if(firewall_config.firewall_enable == true)
+			{
+			     flt_rule_entry.at_rear = true;
+
+			     /* default action for v4 is go DST_NAT unless user set to exception*/
+                             if(firewall_config.rule_action_accept == true)
+			     {
+			        flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+			     }
+			     else
+			     {
+					if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					}
+					else
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+					}
+				}
+		    }
+			else
+			{
+			    flt_rule_entry.at_rear = true;
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+				}
+				else
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+				}
+            }
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+							 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+
+	}
+	else
+	{
+		if (rule_v6 == 0)
+		{
+			memset(m_pFilteringTable, 0, len);
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v6;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			/* Construct ICMP rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.retain_hdr = 1;
+			flt_rule_entry.rule.eq_attrib_type = 0;
+			flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+			memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+			flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+			/* copy filter hdls */
+			dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+			/* End of construct ICMP rule */
+
+			/* v6 default route */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6)) //rt_tbl_wan_v6 rt_tbl_v6
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+
+			/* firewall disable, all traffic are allowed */
+                        if(firewall_config.firewall_enable == true)
+			{
+			   flt_rule_entry.at_rear = true;
+
+			   /* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+                           if(firewall_config.rule_action_accept == true)
+			   {
+			       flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+			   }
+			   else
+			   {
+			       flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+                           }
+		        }
+			else
+			{
+			  flt_rule_entry.at_rear = true;
+			  flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+                        }
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		else
+		{
+			memset(m_pFilteringTable, 0, len);
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v6;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6))
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+            if(firewall_config.firewall_enable == true)
+            {
+			rule_v6 = 0;
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		    			flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+
+				    /* matched rules for v6 go PASS_TO_ROUTE */
+                                    if(firewall_config.rule_action_accept == true)
+			            {
+			                flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			            }
+			            else
+			            {
+					flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+                                    }
+#ifdef FEATURE_IPA_V3
+					flt_rule_entry.rule.hashable = true;
+#endif
+		    			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+					memcpy(&flt_rule_entry.rule.attrib,
+								 &firewall_config.extd_firewall_entries[i].attrib,
+								 sizeof(struct ipa_rule_attrib));
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					/* check if the rule is define as TCP/UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+							/* save v4 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+							/* save v6 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+					}
+					else
+					{
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+							/* save v6 firewall filter rule handler */
+							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+					}
+				}
+			} /* end of firewall ipv6 filter rule add for loop*/
+            }
+
+			/* Construct ICMP rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.retain_hdr = 1;
+			flt_rule_entry.rule.eq_attrib_type = 0;
+			flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+			memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+			flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+			/* copy filter hdls */
+			dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			/* End of construct ICMP rule */
+
+			/* setup default wan filter rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+
+			/* firewall disable, all traffic are allowed */
+                        if(firewall_config.firewall_enable == true)
+			{
+			   flt_rule_entry.at_rear = true;
+
+			   /* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+               if(firewall_config.rule_action_accept == true)
+			   {
+			        flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+			   }
+			   else
+			   {
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+                           }
+		        }
+			else
+			{
+			  flt_rule_entry.at_rear = true;
+			  flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+                        }
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.hashable = true;
+#endif
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+			/* copy filter hdls*/
+			dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+	}
+
+	if(m_pFilteringTable != NULL)
+	{
+		free(m_pFilteringTable);
+	}
+	return IPACM_SUCCESS;
+}
+
+/* configure the initial firewall filter rules */
+int IPACM_Wan::config_dft_firewall_rules_ex(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i;
+	int num_rules = 0, original_num_rules = 0;
+	ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+	ipa_ioc_generate_flt_eq flt_eq;
+	int pos = rule_offset;
+
+	IPACMDBG_H("ip-family: %d; \n", iptype);
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(rules == NULL || rule_offset < 0)
+	{
+		IPACMERR("No filtering table is available.\n");
+		return IPACM_FAILURE;
+	}
+
+	/* default firewall is disable and the rule action is drop */
+	memset(&firewall_config, 0, sizeof(firewall_config));
+	strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+	IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+	if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+	{
+		IPACMDBG_H("QCMAP Firewall XML read OK \n");
+	}
+	else
+	{
+		IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
+	}
+
+	/* add IPv6 frag rule when firewall is enabled*/
+	if(iptype == IPA_IP_v6 &&
+			firewall_config.firewall_enable == true &&
+			check_dft_firewall_rules_attr_mask(&firewall_config))
+	{
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+		flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+#endif
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = false;
+#endif
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		rt_tbl_idx.ip = IPA_IP_v6;
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			return IPACM_FAILURE;
+		}
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+		IPACMDBG_H("IPv6 frag flt rule uses routing table index %d\n", rt_tbl_idx.idx);
+
+		flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+		flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+		flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+
+		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = IPA_IP_v6;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			return IPACM_FAILURE;
+		}
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+			&flt_eq.eq_attrib,
+			sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		pos++;
+		IPACM_Wan::num_v6_flt_rule++;
+	}
+
+	if (iptype == IPA_IP_v4)
+	{
+		original_num_rules = IPACM_Wan::num_v4_flt_rule;
+		if(firewall_config.firewall_enable == true)
+		{
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+					flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+
+					flt_rule_entry.rule.retain_hdr = 1;
+					flt_rule_entry.rule.to_uc = 0;
+					flt_rule_entry.rule.eq_attrib_type = 1;
+
+					/* Accept v4 matched rules*/
+					if(firewall_config.rule_action_accept == true)
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					}
+					else
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+					}
+#ifdef FEATURE_IPA_V3
+					flt_rule_entry.rule.hashable = true;
+#endif
+					memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+					rt_tbl_idx.ip = iptype;
+					if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
+					{
+						strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+					}
+					else /*pass to dst nat*/
+					{
+						strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
+					}
+					rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+					if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+					{
+						IPACMERR("Failed to get routing table index from name\n");
+						return IPACM_FAILURE;
+					}
+					flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+					IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+					memcpy(&flt_rule_entry.rule.attrib,
+						&firewall_config.extd_firewall_entries[i].attrib,
+						sizeof(struct ipa_rule_attrib));
+
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+					/* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+						pos++;
+						num_firewall_v4++;
+						IPACM_Wan::num_v4_flt_rule++;
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+						pos++;
+						num_firewall_v4++;
+						IPACM_Wan::num_v4_flt_rule++;
+					}
+					else
+					{
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+						pos++;
+						num_firewall_v4++;
+						IPACM_Wan::num_v4_flt_rule++;
+					}
+				}
+			} /* end of firewall ipv4 filter rule add for loop*/
+		}
+		/* configure default filter rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+
+		/* firewall disable, all traffic are allowed */
+		if(firewall_config.firewall_enable == true)
+		{
+			/* default action for v4 is go DST_NAT unless user set to exception*/
+			if(firewall_config.rule_action_accept == true)
+			{
+				flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			}
+			else
+			{
+				flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+			}
+		}
+		else
+		{
+			if(isWan_Bridge_Mode())
+			{
+				IPACMDBG_H("ODU is in bridge mode. \n");
+				flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			}
+			else
+			{
+				flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+			}
+		}
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		rt_tbl_idx.ip = iptype;
+
+		if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
+		{
+			strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		}
+		else /*pass to dst nat*/
+		{
+			strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
+		}
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			return IPACM_FAILURE;
+		}
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		memcpy(&flt_rule_entry.rule.attrib,
+			&rx_prop->rx[0].attrib,
+			sizeof(struct ipa_rule_attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+		change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			return IPACM_FAILURE;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+			&flt_eq.eq_attrib,
+			sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		IPACMDBG_H("Filter rule attrib mask: 0x%x\n",	rules[pos].rule.attrib.attrib_mask);
+		pos++;
+		num_firewall_v4++;
+		IPACM_Wan::num_v4_flt_rule++;
+
+		num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules - 1;
+	}
+	else
+	{
+		original_num_rules = IPACM_Wan::num_v6_flt_rule;
+
+		if(firewall_config.firewall_enable == true)
+		{
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+					flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+
+					flt_rule_entry.rule.retain_hdr = 1;
+					flt_rule_entry.rule.to_uc = 0;
+					flt_rule_entry.rule.eq_attrib_type = 1;
+					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+					flt_rule_entry.rule.hashable = true;
+#endif
+					memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+					rt_tbl_idx.ip = iptype;
+
+					/* matched rules for v6 go PASS_TO_ROUTE */
+					if(firewall_config.rule_action_accept == true)
+					{
+						strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+					}
+					else
+					{
+						strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+					}
+					rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+					if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+					{
+						IPACMERR("Failed to get routing table index from name\n");
+						return IPACM_FAILURE;
+					}
+					flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+					IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+					memcpy(&flt_rule_entry.rule.attrib,
+						&firewall_config.extd_firewall_entries[i].attrib,
+						sizeof(struct ipa_rule_attrib));
+
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+					/* check if the rule is define as TCP/UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						pos++;
+						num_firewall_v6++;
+						IPACM_Wan::num_v6_flt_rule++;
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						pos++;
+						num_firewall_v6++;
+						IPACM_Wan::num_v6_flt_rule++;
+					}
+					else
+					{
+						memset(&flt_eq, 0, sizeof(flt_eq));
+						memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+						flt_eq.ip = iptype;
+						if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+						{
+							IPACMERR("Failed to get eq_attrib\n");
+							return IPACM_FAILURE;
+						}
+
+						memcpy(&flt_rule_entry.rule.eq_attrib,
+							&flt_eq.eq_attrib,
+							sizeof(flt_rule_entry.rule.eq_attrib));
+						memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						pos++;
+						num_firewall_v6++;
+						IPACM_Wan::num_v6_flt_rule++;
+					}
+				}
+			} /* end of firewall ipv6 filter rule add for loop*/
+		}
+
+		/* setup default wan filter rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		rt_tbl_idx.ip = iptype;
+		/* firewall disable, all traffic are allowed */
+		if(firewall_config.firewall_enable == true)
+		{
+			/* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+			if(firewall_config.rule_action_accept == true)
+			{
+				strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+			}
+			else
+			{
+				strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+			}
+		}
+		else
+		{
+			strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+		}
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			return IPACM_FAILURE;
+		}
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		memcpy(&flt_rule_entry.rule.attrib,
+			&rx_prop->rx[1].attrib,
+			sizeof(struct ipa_rule_attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			return IPACM_FAILURE;
+		}
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+			&flt_eq.eq_attrib,
+			sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		pos++;
+		num_firewall_v6++;
+		IPACM_Wan::num_v6_flt_rule++;
+
+		num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules - 1;
+	}
+	IPACMDBG_H("Constructed %d firewall rules for ip type %d\n", num_rules, iptype);
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::init_fl_rule_ex(ipa_ip_type iptype)
+{
+	int res = IPACM_SUCCESS;
+
+	char *dev_wlan0="wlan0";
+	char *dev_wlan1="wlan1";
+	char *dev_ecm0="ecm0";
+
+	/* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
+	IPACMDBG_H(" dun add producer dependency from %s with registered rx-prop\n", dev_name);
+
+	if(iptype == IPA_IP_v4)
+	{
+		if(modem_ipv4_pdn_index == 0)	/* install ipv4 default modem DL filtering rules only once */
+		{
+			/* reset the num_v4_flt_rule*/
+			IPACM_Wan::num_v4_flt_rule = 0;
+			add_dft_filtering_rule(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4);
+		}
+	}
+	else if(iptype == IPA_IP_v6)
+	{
+		if(modem_ipv6_pdn_index == 0)	/* install ipv6 default modem DL filtering rules only once */
+		{
+			/* reset the num_v6_flt_rule*/
+			IPACM_Wan::num_v6_flt_rule = 0;
+			add_dft_filtering_rule(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6);
+		}
+	}
+	else
+	{
+		IPACMERR("IP type is not expected.\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+	install_wan_filtering_rule(false);
+
+fail:
+	return res;
+}
+
+int IPACM_Wan::add_icmp_alg_rules(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+	int res = IPACM_SUCCESS, i, original_num_rules = 0, num_rules = 0;
+	struct ipa_flt_rule_add flt_rule_entry;
+	IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
+	ipa_ioc_generate_flt_eq flt_eq;
+	ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+
+	if(rules == NULL || rule_offset < 0)
+	{
+		IPACMERR("No filtering table is available.\n");
+		return IPACM_FAILURE;
+	}
+
+	if(iptype == IPA_IP_v4)
+	{
+		original_num_rules = IPACM_Wan::num_v4_flt_rule;
+
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		/* Configuring ICMP filtering rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* Multiple PDNs may exist so keep meta-data */
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		IPACM_Wan::num_v4_flt_rule++;
+
+		/* Configure ALG filtering rules */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+		for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
+		{
+			flt_rule_entry.rule.attrib.src_port = ipacm_config->alg_table[i].port;
+			flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
+
+			memset(&flt_eq, 0, sizeof(flt_eq));
+			memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+			flt_eq.ip = iptype;
+			if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+			{
+				IPACMERR("Failed to get eq_attrib\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			memcpy(&flt_rule_entry.rule.eq_attrib,
+						 &flt_eq.eq_attrib,
+						 sizeof(flt_rule_entry.rule.eq_attrib));
+			memcpy(&(rules[rule_offset + 1 + i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+			IPACM_Wan::num_v4_flt_rule++;
+		}
+
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+		for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
+		{
+			flt_rule_entry.rule.attrib.dst_port = ipacm_config->alg_table[i].port;
+			flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
+
+			memset(&flt_eq, 0, sizeof(flt_eq));
+			memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+			flt_eq.ip = iptype;
+			if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+			{
+				IPACMERR("Failed to get eq_attrib\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+			memcpy(&flt_rule_entry.rule.eq_attrib,
+						 &flt_eq.eq_attrib,
+						 sizeof(flt_rule_entry.rule.eq_attrib));
+
+			memcpy(&(rules[rule_offset + ipacm_config->ipa_num_alg_ports + 1 + i]),
+				&flt_rule_entry,
+				sizeof(struct ipa_flt_rule_add));
+			IPACM_Wan::num_v4_flt_rule++;
+		}
+		num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules;
+	}
+	else /* IPv6 case */
+	{
+		original_num_rules = IPACM_Wan::num_v6_flt_rule;
+
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		/* Configuring ICMP filtering rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[1].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* Multiple PDNs may exist so keep meta-data */
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+		flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		IPACM_Wan::num_v6_flt_rule++;
+
+		num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules;
+	}
+
+fail:
+	IPACMDBG_H("Constructed %d ICMP/ALG rules for ip type %d\n", num_rules, iptype);
+		return res;
+}
+
+int IPACM_Wan::query_ext_prop()
+{
+	int fd, ret = IPACM_SUCCESS, cnt;
+
+	if (iface_query->num_ext_props > 0)
+	{
+		fd = open(IPA_DEVICE_NAME, O_RDWR);
+		IPACMDBG_H("iface query-property \n");
+		if (0 == fd)
+		{
+			IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+			return IPACM_FAILURE;
+		}
+
+		ext_prop = (struct ipa_ioc_query_intf_ext_props *)
+			 calloc(1, sizeof(struct ipa_ioc_query_intf_ext_props) +
+							iface_query->num_ext_props * sizeof(struct ipa_ioc_ext_intf_prop));
+		if(ext_prop == NULL)
+		{
+			IPACMERR("Unable to allocate memory.\n");
+			return IPACM_FAILURE;
+		}
+		memcpy(ext_prop->name, dev_name,
+					 sizeof(dev_name));
+		ext_prop->num_ext_props = iface_query->num_ext_props;
+
+		IPACMDBG_H("Query extended property for iface %s\n", ext_prop->name);
+
+		ret = ioctl(fd, IPA_IOC_QUERY_INTF_EXT_PROPS, ext_prop);
+		if (ret < 0)
+		{
+			IPACMERR("ioctl IPA_IOC_QUERY_INTF_EXT_PROPS failed\n");
+			/* ext_prop memory will free when iface-down*/
+			free(ext_prop);
+			close(fd);
+			return ret;
+		}
+
+		IPACMDBG_H("Wan interface has %d tx props, %d rx props and %d ext props\n",
+				iface_query->num_tx_props, iface_query->num_rx_props, iface_query->num_ext_props);
+
+		for (cnt = 0; cnt < ext_prop->num_ext_props; cnt++)
+		{
+#ifndef FEATURE_IPA_V3
+			IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d flt_hdl: %d\n",
+				cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+				ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].filter_hdl);
+#else /* defined (FEATURE_IPA_V3) */
+			IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d rule_id: %d\n",
+				cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+				ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].rule_id);
+#endif
+		}
+
+		if(IPACM_Wan::is_ext_prop_set == false)
+		{
+			IPACM_Iface::ipacmcfg->SetExtProp(ext_prop);
+			IPACM_Wan::is_ext_prop_set = true;
+		}
+		close(fd);
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::config_wan_firewall_rule(ipa_ip_type iptype)
+{
+	int res = IPACM_SUCCESS;
+
+	IPACMDBG_H("Configure WAN DL firewall rules.\n");
+
+	if(iptype == IPA_IP_v4)
+	{
+		IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+		if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
+		{
+			IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
+
+		if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
+		{
+			IPACMERR("Failed to add firewall filtering rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
+	}
+	else if(iptype == IPA_IP_v6)
+	{
+		IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
+		if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
+		{
+			IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
+
+		if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
+		{
+			IPACMERR("Failed to add firewall filtering rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
+	}
+	else
+	{
+		IPACMERR("IP type is not expected.\n");
+		return IPACM_FAILURE;
+	}
+
+fail:
+	return res;
+}
+
+int IPACM_Wan::add_dft_filtering_rule(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+	struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+	struct ipa_flt_rule_add flt_rule_entry;
+	struct ipa_ioc_generate_flt_eq flt_eq;
+	int res = IPACM_SUCCESS;
+
+	if(rules == NULL)
+	{
+		IPACMERR("No filtering table available.\n");
+		return IPACM_FAILURE;
+	}
+	if(rx_prop == NULL)
+	{
+		IPACMERR("No tx property.\n");
+		return IPACM_FAILURE;
+	}
+
+	if (iptype == IPA_IP_v4)
+	{
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask since we only install default flt rules once for all modem PDN*/
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+
+		change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Broadcast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+
+		change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		IPACM_Wan::num_v4_flt_rule += IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+		IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4, iptype);
+	}
+	else	/*insert rules for ipv6*/
+	{
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask since we only install default flt rules once for all modem PDN*/
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring fec0::/10 Reserved by IETF Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = iptype;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+					 &flt_eq.eq_attrib,
+					 sizeof(flt_rule_entry.rule.eq_attrib));
+
+		memcpy(&(rules[rule_offset + 2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+#ifdef FEATURE_IPA_ANDROID
+		IPACMDBG_H("Add TCP ctrl rules: total num %d\n", IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6);
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap = 0;
+
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+		flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
+		flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+		flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+
+		/* add TCP FIN rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+		memcpy(&(rules[rule_offset + 3]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* add TCP SYN rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+		memcpy(&(rules[rule_offset + 4]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* add TCP RST rule*/
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+		memcpy(&(rules[rule_offset + 5]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+#endif
+
+		IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
+		IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6, iptype);
+	}
+
+fail:
+	return res;
+}
+
+int IPACM_Wan::del_wan_firewall_rule(ipa_ip_type iptype)
+{
+	if(iptype == IPA_IP_v4)
+	{
+		IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+		memset(&IPACM_Wan::flt_rule_v4[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4], 0,
+			(IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4) * sizeof(struct ipa_flt_rule_add));
+	}
+	else if(iptype == IPA_IP_v6)
+	{
+		IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
+		memset(&IPACM_Wan::flt_rule_v6[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6], 0,
+			(IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6) * sizeof(struct ipa_flt_rule_add));
+	}
+	else
+	{
+		IPACMERR("IP type is not expected.\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*for STA mode: clean firewall filter rules */
+int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
+{
+	/* free v4 firewall filter rule */
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if ((iptype == IPA_IP_v4) && (active_v4 == true))
+	{
+		if (num_firewall_v4 > IPACM_MAX_FIREWALL_ENTRIES)
+		{
+			IPACMERR("the number of v4 firewall entries overflow, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		if (num_firewall_v4 != 0)
+		{
+			if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
+																					IPA_IP_v4, num_firewall_v4) == false)
+			{
+				IPACMERR("Error Deleting Filtering rules, aborting...\n");
+				return IPACM_FAILURE;
+			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_firewall_v4);
+		}
+		else
+		{
+			IPACMDBG_H("No ipv4 firewall rules, no need deleted\n");
+		}
+
+		if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
+																				IPA_IP_v4, 1) == false)
+		{
+			IPACMERR("Error Deleting Filtering rules, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+
+		num_firewall_v4 = 0;
+	}
+
+	/* free v6 firewall filter rule */
+	if ((iptype == IPA_IP_v6) && (active_v6 == true))
+	{
+		if (num_firewall_v6 > IPACM_MAX_FIREWALL_ENTRIES)
+		{
+			IPACMERR("the number of v6 firewall entries overflow, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		if (num_firewall_v6 != 0)
+		{
+			if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
+																					IPA_IP_v6, num_firewall_v6) == false)
+			{
+				IPACMERR("Error Deleting Filtering rules, aborting...\n");
+				return IPACM_FAILURE;
+			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_firewall_v6);
+		}
+		else
+		{
+			IPACMDBG_H("No ipv6 firewall rules, no need deleted\n");
+		}
+
+		if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
+																				IPA_IP_v6, 1) == false)
+		{
+			IPACMERR("Error Deleting Filtering rules, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+		if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[2],
+																				IPA_IP_v6, 1) == false)
+		{
+			IPACMERR("Error Deleting Filtering rules, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+
+		if (is_ipv6_frag_firewall_flt_rule_installed &&
+			check_dft_firewall_rules_attr_mask(&firewall_config))
+		{
+			if (m_filtering.DeleteFilteringHdls(&ipv6_frag_firewall_flt_rule_hdl, IPA_IP_v6, 1) == false)
+			{
+				IPACMERR("Error deleting IPv6 frag filtering rules.\n");
+				return IPACM_FAILURE;
+			}
+			is_ipv6_frag_firewall_flt_rule_installed = false;
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+		}
+		num_firewall_v6 = 0;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* for STA mode: wan default route/filter rule delete */
+int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype)
+{
+	uint32_t tx_index;
+	ipacm_cmd_q_data evt_data;
+
+	IPACMDBG_H("got handle_route_del_evt for STA-mode with ip-family:%d \n", iptype);
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+		return IPACM_SUCCESS;
+	}
+
+	is_default_gateway = false;
+	IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
+
+	if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+			((iptype == IPA_IP_v6) && (active_v6 == true)))
+	{
+
+		/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+		    if(iptype != tx_prop->tx[tx_index].ip)
+		    {
+		    	IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d, no RT-rule deleted\n",
+		    					    tx_index, tx_prop->tx[tx_index].ip,iptype);
+		    	continue;
+		    }
+
+			if (iptype == IPA_IP_v4)
+			{
+		    	IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
+
+				if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4) == false)
+				{
+					IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
+					return IPACM_FAILURE;
+				}
+			}
+			else
+			{
+		    	IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
+
+				if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6) == false)
+				{
+					IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
+					return IPACM_FAILURE;
+				}
+			}
+		}
+
+		/* Delete the default wan route*/
+		if (iptype == IPA_IP_v6)
+		{
+		   	IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
+			if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
+			{
+			IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
+				return IPACM_FAILURE;
+			}
+		}
+		ipacm_event_iface_up *wandown_data;
+		wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+		if (wandown_data == NULL)
+		{
+			IPACMERR("Unable to allocate memory\n");
+			return IPACM_FAILURE;
+		}
+		memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
+
+		if (iptype == IPA_IP_v4)
+		{
+			wandown_data->ipv4_addr = wan_v4_addr;
+			if (m_is_sta_mode!=Q6_WAN)
+			{
+				wandown_data->is_sta = true;
+			}
+			else
+			{
+				wandown_data->is_sta = false;
+			}
+			evt_data.event = IPA_HANDLE_WAN_DOWN;
+			evt_data.evt_data = (void *)wandown_data;
+			/* Insert IPA_HANDLE_WAN_DOWN to command queue */
+			IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 (%d.%d.%d.%d) \n",
+					(unsigned char)(wandown_data->ipv4_addr),
+					(unsigned char)(wandown_data->ipv4_addr >> 8),
+					(unsigned char)(wandown_data->ipv4_addr >> 16),
+					(unsigned char)(wandown_data->ipv4_addr >> 24));
+
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+			IPACMDBG_H("setup wan_up/active_v4= false \n");
+			IPACM_Wan::wan_up = false;
+			active_v4 = false;
+			if(IPACM_Wan::wan_up_v6)
+			{
+				IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+		else
+		{
+			if (m_is_sta_mode!=Q6_WAN)
+			{
+				wandown_data->is_sta = true;
+			}
+			else
+			{
+				wandown_data->is_sta = false;
+			}
+			memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
+			evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
+			evt_data.evt_data = (void *)wandown_data;
+			/* Insert IPA_HANDLE_WAN_DOWN to command queue */
+			IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+			IPACMDBG_H("setup wan_up_v6/active_v6= false \n");
+			IPACM_Wan::wan_up_v6 = false;
+			active_v6 = false;
+			if(IPACM_Wan::wan_up)
+			{
+				IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+	}
+	else
+	{
+		IPACMDBG_H(" The default WAN routing rules are deleted already \n");
+	}
+
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::handle_route_del_evt_ex(ipa_ip_type iptype)
+{
+	ipacm_cmd_q_data evt_data;
+
+	IPACMDBG_H("got handle_route_del_evt_ex with ip-family:%d \n", iptype);
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+		return IPACM_SUCCESS;
+	}
+
+	is_default_gateway = false;
+	IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
+
+	if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+		((iptype == IPA_IP_v6) && (active_v6 == true)))
+	{
+
+		/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+
+		/* Delete the default route*/
+		if (iptype == IPA_IP_v6)
+		{
+			IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
+			if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
+			{
+				IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
+				return IPACM_FAILURE;
+			}
+		}
+
+		ipacm_event_iface_up *wandown_data;
+		wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+		if (wandown_data == NULL)
+		{
+			IPACMERR("Unable to allocate memory\n");
+			return IPACM_FAILURE;
+		}
+		memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
+
+		if (iptype == IPA_IP_v4)
+		{
+			wandown_data->ipv4_addr = wan_v4_addr;
+			if (m_is_sta_mode!=Q6_WAN)
+			{
+				wandown_data->is_sta = true;
+			}
+			else
+			{
+				wandown_data->is_sta = false;
+			}
+			evt_data.event = IPA_HANDLE_WAN_DOWN;
+			evt_data.evt_data = (void *)wandown_data;
+			/* Insert IPA_HANDLE_WAN_DOWN to command queue */
+			IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 with address: 0x%x\n", wan_v4_addr);
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+			IPACMDBG_H("setup wan_up/active_v4= false \n");
+			IPACM_Wan::wan_up = false;
+			active_v4 = false;
+			if(IPACM_Wan::wan_up_v6)
+			{
+				IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+		else
+		{
+			if (m_is_sta_mode!=Q6_WAN)
+			{
+				wandown_data->is_sta = true;
+			}
+			else
+			{
+				wandown_data->is_sta = false;
+			}
+			memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
+			evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
+			evt_data.evt_data = (void *)wandown_data;
+			IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN_V6 for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+			IPACMDBG_H("setup wan_up_v6/active_v6= false \n");
+			IPACM_Wan::wan_up_v6 = false;
+			active_v6 = false;
+			if(IPACM_Wan::wan_up)
+			{
+				IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+	}
+	else
+	{
+		IPACMDBG_H(" The default WAN routing rules are deleted already \n");
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* configure the initial embms filter rules */
+int IPACM_Wan::config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, ipa_ioc_add_flt_rule *pFilteringTable_v6)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+	struct ipa_ioc_generate_flt_eq flt_eq;
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(pFilteringTable_v4 == NULL || pFilteringTable_v6 == NULL)
+	{
+		IPACMERR("Either v4 or v6 filtering table is empty.\n");
+		return IPACM_FAILURE;
+	}
+
+	/* set up ipv4 odu rule*/
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+	/* get eMBMS ODU tbl index*/
+	memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+	strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, IPA_RESOURCE_NAME_MAX);
+	rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+	rt_tbl_idx.ip = IPA_IP_v4;
+	if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+	{
+		IPACMERR("Failed to get routing table index from name\n");
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.at_rear = false;
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+	flt_rule_entry.rule.hashable = true;
+#endif
+	flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(struct ipa_rule_attrib));
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+	memset(&flt_eq, 0, sizeof(flt_eq));
+	memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+	flt_eq.ip = IPA_IP_v4;
+	if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+	{
+		IPACMERR("Failed to get eq_attrib\n");
+		return IPACM_FAILURE;
+	}
+	memcpy(&flt_rule_entry.rule.eq_attrib,
+				 &flt_eq.eq_attrib,
+				 sizeof(flt_rule_entry.rule.eq_attrib));
+
+	memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+	/* construc v6 rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+	/* get eMBMS ODU tbl*/
+	memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+	strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, IPA_RESOURCE_NAME_MAX);
+	rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+	rt_tbl_idx.ip = IPA_IP_v6;
+	if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+	{
+		IPACMERR("Failed to get routing table index from name\n");
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.at_rear = false;
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+	flt_rule_entry.rule.hashable = true;
+#endif
+	flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(struct ipa_rule_attrib));
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+	memset(&flt_eq, 0, sizeof(flt_eq));
+	memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+	flt_eq.ip = IPA_IP_v6;
+	if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+	{
+		IPACMERR("Failed to get eq_attrib\n");
+		return IPACM_FAILURE;
+	}
+	memcpy(&flt_rule_entry.rule.eq_attrib,
+				 &flt_eq.eq_attrib,
+				 sizeof(flt_rule_entry.rule.eq_attrib));
+
+	memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+	return IPACM_SUCCESS;
+}
+
+
+/*for STA mode: handle wan-iface down event */
+int IPACM_Wan::handle_down_evt()
+{
+	int res = IPACM_SUCCESS;
+	int i;
+
+	IPACMDBG_H(" wan handle_down_evt \n");
+
+	/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+	IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+	if (tx_prop != NULL)
+	{
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+	}
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
+	/* make sure default routing rules and firewall rules are deleted*/
+	if (active_v4)
+	{
+	   	if (rx_prop != NULL)
+	    {
+			del_dft_firewall_rules(IPA_IP_v4);
+		}
+		handle_route_del_evt(IPA_IP_v4);
+		IPACMDBG_H("Delete default v4 routing rules\n");
+	}
+
+	if (active_v6)
+	{
+	   	if (rx_prop != NULL)
+	    {
+			del_dft_firewall_rules(IPA_IP_v6);
+		}
+		handle_route_del_evt(IPA_IP_v6);
+		IPACMDBG_H("Delete default v6 routing rules\n");
+	}
+
+	/* Delete default v4 RT rule */
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG_H("Delete default v4 routing rules\n");
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+		{
+		   IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* delete default v6 RT rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		IPACMDBG_H("Delete default v6 routing rules\n");
+		/* May have multiple ipv6 iface-routing rules*/
+		for (i = 0; i < 2*num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+
+		IPACMDBG_H("finished delete default v6 RT rules\n ");
+	}
+
+
+	/* clean wan-client header, routing rules */
+	IPACMDBG_H("left %d wan clients need to be deleted \n ", num_wan_client);
+	for (i = 0; i < num_wan_client; i++)
+	{
+			/* Del NAT rules before ipv4 RT rules are delete */
+			if(get_client_memptr(wan_client, i)->ipv4_set == true)
+			{
+				IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wan_client, i)->v4_addr);
+				CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, i)->v4_addr);
+			}
+
+			if (delete_wan_rtrules(i, IPA_IP_v4))
+			{
+				IPACMERR("unbale to delete wan-client v4 route rules for index %d\n", i);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+			if (delete_wan_rtrules(i, IPA_IP_v6))
+			{
+				IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+			IPACMDBG_H("Delete %d client header\n", num_wan_client);
+
+
+			if(get_client_memptr(wan_client, i)->ipv4_header_set == true)
+			{
+				if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v4)
+					== false)
+				{
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+			}
+
+			if(get_client_memptr(wan_client, i)->ipv6_header_set == true)
+			{
+			if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v6)
+					== false)
+			{
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			}
+	} /* end of for loop */
+
+	/* free the edm clients cache */
+	IPACMDBG_H("Free wan clients cache\n");
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true)
+	{
+		handle_software_routing_disable();
+	}
+
+	/* free filter rule handlers */
+	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+																				IPA_IP_v4,
+																				IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Delete Filtering rules, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+
+		IPACMDBG_H("finished delete default v4 filtering rules\n ");
+	}
+
+
+	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+																				IPA_IP_v6,
+																				IPV6_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+
+		if(num_ipv6_dest_flt_rule > 0 && num_ipv6_dest_flt_rule <= MAX_DEFAULT_v6_ROUTE_RULES)
+		{
+			if(m_filtering.DeleteFilteringHdls(ipv6_dest_flt_rule_hdl,  IPA_IP_v6, num_ipv6_dest_flt_rule) == false)
+			{
+				IPACMERR("Failed to delete ipv6 dest flt rules.\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_ipv6_dest_flt_rule);
+		}
+		IPACMDBG_H("finished delete default v6 filtering rules\n ");
+	}
+	if(hdr_proc_hdl_dummy_v6)
+	{
+		if(m_header.DeleteHeaderProcCtx(hdr_proc_hdl_dummy_v6) == false)
+		{
+			IPACMERR("Failed to delete hdr_proc_hdl_dummy_v6\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+	if(hdr_hdl_dummy_v6)
+	{
+		if (m_header.DeleteHeaderHdl(hdr_hdl_dummy_v6) == false)
+		{
+			IPACMERR("Failed to delete hdr_hdl_dummy_v6\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+fail:
+	if (tx_prop != NULL)
+	{
+		free(tx_prop);
+	}
+	if (rx_prop != NULL)
+	{
+		free(rx_prop);
+	}
+	if (iface_query != NULL)
+	{
+		free(iface_query);
+	}
+	if (wan_route_rule_v4_hdl != NULL)
+	{
+		free(wan_route_rule_v4_hdl);
+	}
+	if (wan_route_rule_v6_hdl != NULL)
+	{
+		free(wan_route_rule_v6_hdl);
+	}
+	if (wan_route_rule_v6_hdl_a5 != NULL)
+	{
+		free(wan_route_rule_v6_hdl_a5);
+	}
+	if (wan_client != NULL)
+	{
+		free(wan_client);
+	}
+	close(m_fd_ipa);
+	return res;
+}
+
+int IPACM_Wan::handle_down_evt_ex()
+{
+	int res = IPACM_SUCCESS;
+	int i, tether_total;
+	int ipa_if_num_tether_tmp[IPA_MAX_IFACE_ENTRIES];
+
+	IPACMDBG_H(" wan handle_down_evt \n");
+
+	/* free ODU filter rule handlers */
+	if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
+	{
+		embms_is_on = false;
+		/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		if (tx_prop != NULL)
+		{
+			IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+			IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		}
+
+		if (rx_prop != NULL)
+		{
+			install_wan_filtering_rule(false);
+			IPACMDBG("finished delete embms filtering rule\n ");
+		}
+		goto fail;
+	}
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
+	if(ip_type == IPA_IP_v4)
+	{
+		num_ipv4_modem_pdn--;
+		IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
+		/* only when default gw goes down we post WAN_DOWN event*/
+		if(is_default_gateway == true)
+		{
+			IPACM_Wan::wan_up = false;
+			del_wan_firewall_rule(IPA_IP_v4);
+			install_wan_filtering_rule(false);
+			handle_route_del_evt_ex(IPA_IP_v4);
+#ifdef FEATURE_IPA_ANDROID
+			/* posting wan_down_tether for all lan clients */
+			for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+			{
+				ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
+			}
+			tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
+			for (i=0; i < tether_total; i++)
+			{
+				post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
+				IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
+					i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+			}
+#endif
+			if(IPACM_Wan::wan_up_v6)
+			{
+				IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+
+		/* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
+		if(num_ipv4_modem_pdn == 0)
+		{
+			IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
+		IPACM_Wan::num_v4_flt_rule = 0;
+		memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+		install_wan_filtering_rule(false);
+		}
+
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+	else if(ip_type == IPA_IP_v6)
+	{
+	    if (num_dft_rt_v6 > 1)
+			num_ipv6_modem_pdn--;
+		IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
+		/* only when default gw goes down we post WAN_DOWN event*/
+		if(is_default_gateway == true)
+		{
+			IPACM_Wan::wan_up_v6 = false;
+			del_wan_firewall_rule(IPA_IP_v6);
+			install_wan_filtering_rule(false);
+			handle_route_del_evt_ex(IPA_IP_v6);
+#ifdef FEATURE_IPA_ANDROID //sky
+			/* posting wan_down_tether for all lan clients */
+			for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+			{
+				ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
+			}
+			tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
+			for (i=0; i < tether_total; i++)
+			{
+				post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
+				IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
+					i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+			}
+#endif
+			if(IPACM_Wan::wan_up)
+			{
+				IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+			}
+			else
+			{
+				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+			}
+		}
+
+		/* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
+		if(num_ipv6_modem_pdn == 0)
+		{
+			IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
+		IPACM_Wan::num_v6_flt_rule = 0;
+		memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+		install_wan_filtering_rule(false);
+		}
+
+		for (i = 0; i < 2*num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+	else
+	{
+		num_ipv4_modem_pdn--;
+		IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
+	    if (num_dft_rt_v6 > 1)
+			num_ipv6_modem_pdn--;
+		IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
+		/* only when default gw goes down we post WAN_DOWN event*/
+		if(is_default_gateway == true)
+		{
+			IPACM_Wan::wan_up = false;
+			del_wan_firewall_rule(IPA_IP_v4);
+			handle_route_del_evt_ex(IPA_IP_v4);
+#ifdef FEATURE_IPA_ANDROID
+			/* posting wan_down_tether for all lan clients */
+			for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+			{
+				ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
+			}
+			tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
+			for (i=0; i < tether_total; i++)
+			{
+				post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
+				IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
+					i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+			}
+#endif
+			IPACM_Wan::wan_up_v6 = false;
+			del_wan_firewall_rule(IPA_IP_v6);
+			handle_route_del_evt_ex(IPA_IP_v6);
+#ifdef FEATURE_IPA_ANDROID
+			/* posting wan_down_tether for all lan clients */
+			for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+			{
+				ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
+			}
+			tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
+			for (i=0; i < tether_total; i++)
+			{
+				post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
+				IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
+					i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+			}
+#endif
+			memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+
+			install_wan_filtering_rule(false);
+		}
+
+		/* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
+		if(num_ipv4_modem_pdn == 0)
+		{
+			IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
+			IPACM_Wan::num_v4_flt_rule = 0;
+			memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+			install_wan_filtering_rule(false);
+		}
+		/* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
+		if(num_ipv6_modem_pdn == 0)
+		{
+			IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
+			IPACM_Wan::num_v6_flt_rule = 0;
+			memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+			install_wan_filtering_rule(false);
+		}
+
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		for (i = 0; i < 2*num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true)
+	{
+		handle_software_routing_disable();
+	}
+
+fail:
+	if (tx_prop != NULL)
+	{
+		free(tx_prop);
+	}
+	if (rx_prop != NULL)
+	{
+		free(rx_prop);
+	}
+	if (ext_prop != NULL)
+	{
+		free(ext_prop);
+	}
+	if (iface_query != NULL)
+	{
+		free(iface_query);
+	}
+	if (wan_route_rule_v4_hdl != NULL)
+	{
+		free(wan_route_rule_v4_hdl);
+	}
+	if (wan_route_rule_v6_hdl != NULL)
+	{
+		free(wan_route_rule_v6_hdl);
+	}
+	if (wan_route_rule_v6_hdl_a5 != NULL)
+	{
+		free(wan_route_rule_v6_hdl_a5);
+	}
+	if (wan_client != NULL)
+	{
+		free(wan_client);
+	}
+	close(m_fd_ipa);
+	return res;
+}
+
+int IPACM_Wan::install_wan_filtering_rule(bool is_sw_routing)
+{
+	int len, res = IPACM_SUCCESS;
+	uint8_t mux_id;
+	ipa_ioc_add_flt_rule *pFilteringTable_v4 = NULL;
+	ipa_ioc_add_flt_rule *pFilteringTable_v6 = NULL;
+
+	mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
+	if(rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+	if (is_sw_routing == true ||
+			IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+	{
+		/* contruct SW-RT rules to Q6*/
+		struct ipa_flt_rule_add flt_rule_entry;
+		struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+		ipa_ioc_generate_flt_eq flt_eq;
+
+		IPACMDBG("\n");
+		if (softwarerouting_act == true)
+		{
+			IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
+								IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+			return IPACM_SUCCESS;
+		}
+
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+		pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+		if (pFilteringTable_v4 == NULL)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+		memset(pFilteringTable_v4, 0, len);
+		IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is 1\n");
+
+		pFilteringTable_v4->commit = 1;
+		pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+		pFilteringTable_v4->global = false;
+		pFilteringTable_v4->ip = IPA_IP_v4;
+		pFilteringTable_v4->num_rules = (uint8_t)1;
+
+		/* Configuring Software-Routing Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = IPA_IP_v4;
+		if(ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx) < 0)
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+		memcpy(&flt_rule_entry.rule.attrib,
+					&rx_prop->rx[0].attrib,
+					sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.retain_hdr = 0;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = IPA_IP_v4;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+			&flt_eq.eq_attrib,
+			sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+		pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+		if (pFilteringTable_v6 == NULL)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			free(pFilteringTable_v4);
+			return IPACM_FAILURE;
+		}
+		memset(pFilteringTable_v6, 0, len);
+		IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is 1\n");
+
+		pFilteringTable_v6->commit = 1;
+		pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+		pFilteringTable_v6->global = false;
+		pFilteringTable_v6->ip = IPA_IP_v6;
+		pFilteringTable_v6->num_rules = (uint8_t)1;
+
+		/* Configuring Software-Routing Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+		rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+		rt_tbl_idx.ip = IPA_IP_v6;
+		if(ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx) < 0)
+		{
+			IPACMERR("Failed to get routing table index from name\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = true;
+#endif
+		flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+		memcpy(&flt_rule_entry.rule.attrib,
+					&rx_prop->rx[0].attrib,
+					sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.retain_hdr = 0;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 1;
+
+		memset(&flt_eq, 0, sizeof(flt_eq));
+		memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+		flt_eq.ip = IPA_IP_v6;
+		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+		{
+			IPACMERR("Failed to get eq_attrib\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		memcpy(&flt_rule_entry.rule.eq_attrib,
+			&flt_eq.eq_attrib,
+			sizeof(flt_rule_entry.rule.eq_attrib));
+		memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		softwarerouting_act = true;
+		/* end of contruct SW-RT rules to Q6*/
+	}
+	else
+	{
+		if(embms_is_on == false)
+		{
+			if(IPACM_Wan::num_v4_flt_rule > 0)
+			{
+				len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v4_flt_rule * sizeof(struct ipa_flt_rule_add);
+				pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+
+				IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule);
+
+				if (pFilteringTable_v4 == NULL)
+				{
+					IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+					return IPACM_FAILURE;
+				}
+				memset(pFilteringTable_v4, 0, len);
+				pFilteringTable_v4->commit = 1;
+				pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+				pFilteringTable_v4->global = false;
+				pFilteringTable_v4->ip = IPA_IP_v4;
+				pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule;
+
+				memcpy(pFilteringTable_v4->rules, IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
+			}
+
+			if(IPACM_Wan::num_v6_flt_rule > 0)
+			{
+				len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v6_flt_rule * sizeof(struct ipa_flt_rule_add);
+				pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+
+				IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule);
+
+				if (pFilteringTable_v6 == NULL)
+				{
+					IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+					free(pFilteringTable_v4);
+					return IPACM_FAILURE;
+				}
+				memset(pFilteringTable_v6, 0, len);
+				pFilteringTable_v6->commit = 1;
+				pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+				pFilteringTable_v6->global = false;
+				pFilteringTable_v6->ip = IPA_IP_v6;
+				pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule;
+
+				memcpy(pFilteringTable_v6->rules, IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
+			}
+		}
+		else	//embms is on, always add 1 embms rule on top of WAN DL flt table
+		{
+			/* allocate ipv4 filtering table */
+			len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v4_flt_rule) * sizeof(struct ipa_flt_rule_add);
+			pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+			IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule + 1);
+			if (pFilteringTable_v4 == NULL)
+			{
+				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+			memset(pFilteringTable_v4, 0, len);
+			pFilteringTable_v4->commit = 1;
+			pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+			pFilteringTable_v4->global = false;
+			pFilteringTable_v4->ip = IPA_IP_v4;
+			pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule + 1;
+
+			/* allocate ipv6 filtering table */
+			len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v6_flt_rule) * sizeof(struct ipa_flt_rule_add);
+			pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+			IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule + 1);
+			if (pFilteringTable_v6 == NULL)
+			{
+				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+				free(pFilteringTable_v4);
+				return IPACM_FAILURE;
+			}
+			memset(pFilteringTable_v6, 0, len);
+			pFilteringTable_v6->commit = 1;
+			pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+			pFilteringTable_v6->global = false;
+			pFilteringTable_v6->ip = IPA_IP_v6;
+			pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule + 1;
+
+			config_dft_embms_rules(pFilteringTable_v4, pFilteringTable_v6);
+			if(IPACM_Wan::num_v4_flt_rule > 0)
+			{
+				memcpy(&(pFilteringTable_v4->rules[1]), IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
+			}
+
+			if(IPACM_Wan::num_v6_flt_rule > 0)
+			{
+				memcpy(&(pFilteringTable_v6->rules[1]), IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
+			}
+		}
+	}
+
+	if(false == m_filtering.AddWanDLFilteringRule(pFilteringTable_v4, pFilteringTable_v6, mux_id))
+	{
+		IPACMERR("Failed to install WAN DL filtering table.\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+
+fail:
+	if(pFilteringTable_v4 != NULL)
+	{
+		free(pFilteringTable_v4);
+	}
+	if(pFilteringTable_v6 != NULL)
+	{
+		free(pFilteringTable_v6);
+	}
+	return res;
+}
+
+void IPACM_Wan::change_to_network_order(ipa_ip_type iptype, ipa_rule_attrib* attrib)
+{
+	if(attrib == NULL)
+	{
+		IPACMERR("Attribute pointer is NULL.\n");
+		return;
+	}
+
+	if(iptype == IPA_IP_v6)
+	{
+		int i;
+		for(i=0; i<4; i++)
+		{
+			attrib->u.v6.src_addr[i] = htonl(attrib->u.v6.src_addr[i]);
+			attrib->u.v6.src_addr_mask[i] = htonl(attrib->u.v6.src_addr_mask[i]);
+			attrib->u.v6.dst_addr[i] = htonl(attrib->u.v6.dst_addr[i]);
+			attrib->u.v6.dst_addr_mask[i] = htonl(attrib->u.v6.dst_addr_mask[i]);
+		}
+	}
+	else
+	{
+		IPACMDBG_H("IP type is not IPv6, do nothing: %d\n", iptype);
+	}
+
+	return;
+}
+
+bool IPACM_Wan::is_global_ipv6_addr(uint32_t* ipv6_addr)
+{
+	if(ipv6_addr == NULL)
+	{
+		IPACMERR("IPv6 address is empty.\n");
+		return false;
+	}
+	IPACMDBG_H("Get ipv6 address with first word 0x%08x.\n", ipv6_addr[0]);
+
+	uint32_t ipv6_link_local_prefix, ipv6_link_local_prefix_mask;
+	ipv6_link_local_prefix = 0xFE800000;
+	ipv6_link_local_prefix_mask = 0xFFC00000;
+	if((ipv6_addr[0] & ipv6_link_local_prefix_mask) == (ipv6_link_local_prefix & ipv6_link_local_prefix_mask))
+	{
+		IPACMDBG_H("This IPv6 address is link local.\n");
+		return false;
+	}
+	else
+	{
+		IPACMDBG_H("This IPv6 address is not link local.\n");
+		return true;
+	}
+}
+
+/* handle STA WAN-client */
+/* handle WAN client initial, construct full headers (tx property) */
+int IPACM_Wan::handle_wan_hdr_init(uint8_t *mac_addr)
+{
+
+#define WAN_IFACE_INDEX_LEN 2
+
+	int res = IPACM_SUCCESS, len = 0;
+	char index[WAN_IFACE_INDEX_LEN];
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+	uint32_t cnt;
+	int clnt_indx;
+
+	clnt_indx = get_wan_client_index(mac_addr);
+
+	if (clnt_indx != IPACM_INVALID_INDEX)
+	{
+		IPACMERR("eth client is found/attached already with index %d \n", clnt_indx);
+		return IPACM_FAILURE;
+	}
+
+	/* add header to IPA */
+	if (num_wan_client >= IPA_MAX_NUM_WAN_CLIENTS)
+	{
+		IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_WAN_CLIENTS);
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG_H("WAN client number: %d\n", num_wan_client);
+
+	memcpy(get_client_memptr(wan_client, num_wan_client)->mac,
+				 mac_addr,
+				 sizeof(get_client_memptr(wan_client, num_wan_client)->mac));
+
+	IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(wan_client, num_wan_client)->mac[0],
+					 get_client_memptr(wan_client, num_wan_client)->mac[1],
+					 get_client_memptr(wan_client, num_wan_client)->mac[2],
+					 get_client_memptr(wan_client, num_wan_client)->mac[3],
+					 get_client_memptr(wan_client, num_wan_client)->mac[4],
+					 get_client_memptr(wan_client, num_wan_client)->mac[5]);
+
+	/* add header to IPA */
+	if(tx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+		if (pHeaderDescriptor == NULL)
+		{
+			IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+			return IPACM_FAILURE;
+		}
+
+		/* copy partial header for v4*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+				 if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+				 {
+								IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+								memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+								memcpy(sCopyHeader.name,
+											 tx_prop->tx[cnt].hdr_name,
+											 sizeof(sCopyHeader.name));
+
+								IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+								if (m_header.CopyHeader(&sCopyHeader) == false)
+								{
+									PERROR("ioctl copy header failed");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+								IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+								if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+								{
+									IPACMERR("header oversize\n");
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+								else
+								{
+									memcpy(pHeaderDescriptor->hdr[0].hdr,
+												 sCopyHeader.hdr,
+												 sCopyHeader.hdr_len);
+								}
+
+								/* copy client mac_addr to partial header */
+								IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
+										sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+
+								/* only copy 6 bytes mac-address */
+								if(sCopyHeader.is_eth2_ofst_valid == false)
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
+											mac_addr, IPA_MAC_ADDR_SIZE);
+								}
+								else
+								{
+									memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+											mac_addr, IPA_MAC_ADDR_SIZE);
+								}
+
+
+								pHeaderDescriptor->commit = true;
+								pHeaderDescriptor->num_hdrs = 1;
+
+								memset(pHeaderDescriptor->hdr[0].name, 0,
+											 sizeof(pHeaderDescriptor->hdr[0].name));
+
+								snprintf(index,sizeof(index), "%d", ipa_if_num);
+								strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+								pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+								if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+								{
+									IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								snprintf(index,sizeof(index), "%d", header_name_count);
+								if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+								{
+									IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+									res = IPACM_FAILURE;
+									goto fail;
+								}
+
+								pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+								pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+								pHeaderDescriptor->hdr[0].is_partial = 0;
+								pHeaderDescriptor->hdr[0].status = -1;
+
+					 if (m_header.AddHeader(pHeaderDescriptor) == false ||
+							pHeaderDescriptor->hdr[0].status != 0)
+					 {
+						IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+						res = IPACM_FAILURE;
+						goto fail;
+					 }
+
+					get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+					IPACMDBG_H("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
+												 num_wan_client,
+												 pHeaderDescriptor->hdr[0].name,
+												 get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4);
+									get_client_memptr(wan_client, num_wan_client)->ipv4_header_set=true;
+
+					break;
+				 }
+		}
+
+
+		/* copy partial header for v6*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+			{
+
+				IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+				memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+				memcpy(sCopyHeader.name,
+						tx_prop->tx[cnt].hdr_name,
+							sizeof(sCopyHeader.name));
+
+				IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+				if (m_header.CopyHeader(&sCopyHeader) == false)
+				{
+					PERROR("ioctl copy header failed");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+				IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+				if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+				{
+					IPACMERR("header oversize\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					memcpy(pHeaderDescriptor->hdr[0].hdr,
+							sCopyHeader.hdr,
+							sCopyHeader.hdr_len);
+				}
+
+				/* copy client mac_addr to partial header */
+				if(sCopyHeader.is_eth2_ofst_valid == false)
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
+								 mac_addr, IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+				}
+				else
+				{
+					memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+								 mac_addr, IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+				}
+
+
+				pHeaderDescriptor->commit = true;
+				pHeaderDescriptor->num_hdrs = 1;
+
+				memset(pHeaderDescriptor->hdr[0].name, 0,
+					 sizeof(pHeaderDescriptor->hdr[0].name));
+
+				snprintf(index,sizeof(index), "%d", ipa_if_num);
+				strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+				pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+				if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				snprintf(index,sizeof(index), "%d", header_name_count);
+				if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+				pHeaderDescriptor->hdr[0].is_partial = 0;
+				pHeaderDescriptor->hdr[0].status = -1;
+
+				if (m_header.AddHeader(pHeaderDescriptor) == false ||
+						pHeaderDescriptor->hdr[0].status != 0)
+				{
+					IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+				IPACMDBG_H("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
+						 num_wan_client,
+						 pHeaderDescriptor->hdr[0].name,
+									 get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6);
+
+									get_client_memptr(wan_client, num_wan_client)->ipv6_header_set=true;
+
+				break;
+
+			}
+		}
+		/* initialize wifi client*/
+		get_client_memptr(wan_client, num_wan_client)->route_rule_set_v4 = false;
+		get_client_memptr(wan_client, num_wan_client)->route_rule_set_v6 = 0;
+		get_client_memptr(wan_client, num_wan_client)->ipv4_set = false;
+		get_client_memptr(wan_client, num_wan_client)->ipv6_set = 0;
+		num_wan_client++;
+		header_name_count++; //keep increasing header_name_count
+		res = IPACM_SUCCESS;
+		IPACMDBG_H("eth client number: %d\n", num_wan_client);
+	}
+	else
+	{
+		return res;
+	}
+fail:
+	free(pHeaderDescriptor);
+
+	return res;
+}
+
+/*handle eth client */
+int IPACM_Wan::handle_wan_client_ipaddr(ipacm_event_data_all *data)
+{
+	int clnt_indx;
+	int v6_num;
+
+	IPACMDBG_H("number of wan clients: %d\n", num_wan_client);
+	IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 data->mac_addr[0],
+					 data->mac_addr[1],
+					 data->mac_addr[2],
+					 data->mac_addr[3],
+					 data->mac_addr[4],
+					 data->mac_addr[5]);
+
+	clnt_indx = get_wan_client_index(data->mac_addr);
+
+		if (clnt_indx == IPACM_INVALID_INDEX)
+		{
+			IPACMERR("wan client not found/attached \n");
+			return IPACM_FAILURE;
+		}
+
+	IPACMDBG_H("Ip-type received %d\n", data->iptype);
+	if (data->iptype == IPA_IP_v4)
+	{
+		IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+		if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+		{
+			if (get_client_memptr(wan_client, clnt_indx)->ipv4_set == false)
+			{
+				get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				get_client_memptr(wan_client, clnt_indx)->ipv4_set = true;
+				/* Add NAT rules after ipv4 RT rules are set */
+				CtList->HandleSTAClientAddEvt(data->ipv4_addr);
+			}
+			else
+			{
+			   /* check if client got new IPv4 address*/
+			   if(data->ipv4_addr == get_client_memptr(wan_client, clnt_indx)->v4_addr)
+			   {
+			     IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+				 return IPACM_FAILURE;
+			   }
+			   else
+			   {
+					IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+					/* Del NAT rules before ipv4 RT rules are delete */
+					CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, clnt_indx)->v4_addr);
+					delete_wan_rtrules(clnt_indx,IPA_IP_v4);
+					get_client_memptr(wan_client, clnt_indx)->route_rule_set_v4 = false;
+					get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+					/* Add NAT rules after ipv4 RT rules are set */
+					CtList->HandleSTAClientAddEvt(data->ipv4_addr);
+				}
+			}
+		}
+		else
+		{
+				IPACMDBG_H("Invalid client IPv4 address \n");
+				return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+		{
+		   IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+                   if(get_client_memptr(wan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+		   {
+
+		       for(v6_num=0;v6_num < get_client_memptr(wan_client, clnt_indx)->ipv6_set;v6_num++)
+	               {
+			      if( data->ipv6_addr[0] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][0] &&
+			           data->ipv6_addr[1] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][1] &&
+			  	        data->ipv6_addr[2]== get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][2] &&
+			  	         data->ipv6_addr[3] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][3])
+			      {
+			  	    IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
+			  	    return IPACM_FAILURE; /* not setup the RT rules*/
+			      }
+		       }
+
+		       /* not see this ipv6 before for wifi client*/
+			   get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+			   get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+			   get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+			   get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+			   get_client_memptr(wan_client, clnt_indx)->ipv6_set++;
+		    }
+		    else
+		    {
+		         IPACMDBG_H("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
+			 return IPACM_FAILURE; /* not setup the RT rules*/
+		    }
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wan client routing rule*/
+int IPACM_Wan::handle_wan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	uint32_t tx_index;
+	int wan_index,v6_num;
+	const int NUM = 1;
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+			mac_addr[0], mac_addr[1], mac_addr[2],
+			mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	wan_index = get_wan_client_index(mac_addr);
+	if (wan_index == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("wan client not found/attached \n");
+		return IPACM_SUCCESS;
+	}
+
+	if (iptype==IPA_IP_v4) {
+		IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wan_index, iptype,
+				get_client_memptr(wan_client, wan_index)->ipv4_set,
+				get_client_memptr(wan_client, wan_index)->route_rule_set_v4);
+	} else {
+		IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wan_index, iptype,
+				get_client_memptr(wan_client, wan_index)->ipv6_set,
+				get_client_memptr(wan_client, wan_index)->route_rule_set_v6);
+	}
+
+	/* Add default routing rules if not set yet */
+	if ((iptype == IPA_IP_v4
+				&& get_client_memptr(wan_client, wan_index)->route_rule_set_v4 == false
+				&& get_client_memptr(wan_client, wan_index)->ipv4_set == true)
+			|| (iptype == IPA_IP_v6
+				&& get_client_memptr(wan_client, wan_index)->route_rule_set_v6 < get_client_memptr(wan_client, wan_index)->ipv6_set
+			   ))
+	{
+
+		/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_add));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = (uint8_t)NUM;
+		rt_rule->ip = iptype;
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if(iptype != tx_prop->tx[tx_index].ip)
+			{
+				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+						tx_index, tx_prop->tx[tx_index].ip,iptype);
+				continue;
+			}
+
+			rt_rule_entry = &rt_rule->rules[0];
+			rt_rule_entry->at_rear = 0;
+
+			if (iptype == IPA_IP_v4)
+			{
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wan_index,
+						get_client_memptr(wan_client, wan_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wan_index,
+						get_client_memptr(wan_client, wan_index)->hdr_hdl_v4);
+				strlcpy(rt_rule->rt_tbl_name,
+						IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name,
+						sizeof(rt_rule->rt_tbl_name));
+				rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v4;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, wan_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+				rt_rule_entry->rule.hashable = true;
+#endif
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule addition failed!\n");
+					free(rt_rule);
+					return IPACM_FAILURE;
+				}
+
+				/* copy ipv4 RT hdl */
+				get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4 =
+					rt_rule->rules[0].rt_rule_hdl;
+				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+						get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4, iptype);
+			} else {
+
+				for(v6_num = get_client_memptr(wan_client, wan_index)->route_rule_set_v6;v6_num < get_client_memptr(wan_client, wan_index)->ipv6_set;v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wan_index,
+							get_client_memptr(wan_client, wan_index)->hdr_hdl_v6);
+
+					/* v6 LAN_RT_TBL */
+					strlcpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+					rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+					/* Uplink going to wan clients should go to IPA */
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+					memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v6;;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+					rt_rule_entry->rule.hashable = true;
+#endif
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num], iptype);
+
+					/*Copy same rule to v6 WAN RT TBL*/
+					strlcpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+					rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+					/* Downlink traffic from Wan clients, should go exception */
+					rt_rule_entry->rule.dst = iface_query->excp_pipe;
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = 0;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num], iptype);
+				}
+			}
+
+		} /* end of for loop */
+
+		free(rt_rule);
+
+		if (iptype == IPA_IP_v4)
+		{
+			get_client_memptr(wan_client, wan_index)->route_rule_set_v4 = true;
+		}
+		else
+		{
+			get_client_memptr(wan_client, wan_index)->route_rule_set_v6 = get_client_memptr(wan_client, wan_index)->ipv6_set;
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* TODO Handle wan client routing rules also */
+void IPACM_Wan::handle_wlan_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	uint32_t tx_index = 0;
+
+	IPACMDBG("\n");
+	if (tx_prop == NULL || is_default_gateway == false)
+	{
+		IPACMDBG_H("No tx properties or no default route set yet\n");
+		return;
+	}
+
+	const int NUM = tx_prop->num_tx_props;
+
+	for (tx_index = 0; tx_index < tx_prop->num_tx_props; tx_index++)
+	{
+		if (tx_prop->tx[tx_index].ip != iptype)
+		{
+			IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+					tx_index, tx_prop->tx[tx_index].ip, iptype);
+			continue;
+		}
+
+		if (rt_rule == NULL)
+		{
+			rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+				calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+			if (rt_rule == NULL)
+			{
+				IPACMERR("Unable to allocate memory for modify rt rule\n");
+				return;
+			}
+			IPACMDBG("Allocated memory for %d rules successfully\n", NUM);
+
+			rt_rule->commit = 1;
+			rt_rule->num_rules = 0;
+			rt_rule->ip = iptype;
+		}
+
+		rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+		memcpy(&rt_rule_entry->rule.attrib,
+				&tx_prop->tx[tx_index].attrib,
+				sizeof(rt_rule_entry->rule.attrib));
+		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+		if (iptype == IPA_IP_v4)
+		{
+			rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
+			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+			rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
+			rt_rule_entry->rt_rule_hdl = wan_route_rule_v4_hdl[tx_index];
+		}
+		else
+		{
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+
+			rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
+			rt_rule_entry->rt_rule_hdl = wan_route_rule_v6_hdl[tx_index];
+		}
+		IPACMDBG_H("Header handle: 0x%x\n", rt_rule_entry->rule.hdr_hdl);
+
+		if (isSCCMode)
+		{
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+		}
+		else
+		{
+			IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+					tx_prop->tx[tx_index].alt_dst_pipe);
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+		}
+
+		rt_rule->num_rules++;
+	}
+
+	if (rt_rule != NULL)
+	{
+
+		if (rt_rule->num_rules > 0)
+		{
+			if (false == m_routing.ModifyRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule modify failed!\n");
+				free(rt_rule);
+				return;
+			}
+
+			IPACMDBG("Routing rule modified successfully \n");
+		}
+
+		free(rt_rule);
+	}
+
+	return;
+}
+
+void IPACM_Wan::handle_wan_client_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+
+	uint32_t tx_index = 0, clnt_index =0;
+	int v6_num = 0;
+	const int NUM_RULES = 1;
+
+	int size = sizeof(struct ipa_ioc_mdfy_rt_rule) +
+		NUM_RULES * sizeof(struct ipa_rt_rule_mdfy);
+
+	IPACMDBG("\n");
+
+	if (tx_prop == NULL || is_default_gateway == false)
+	{
+		IPACMDBG_H("No tx properties or no default route set yet\n");
+		return;
+	}
+
+	rt_rule = (struct ipa_ioc_mdfy_rt_rule *)calloc(1, size);
+	if (rt_rule == NULL)
+	{
+		IPACMERR("Unable to allocate memory for modify rt rule\n");
+		return;
+	}
+
+
+	for (clnt_index = 0; clnt_index < num_wan_client; clnt_index++)
+	{
+		if (iptype == IPA_IP_v4)
+		{
+			IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n",
+					clnt_index, iptype,
+					get_client_memptr(wan_client, clnt_index)->ipv4_set,
+					get_client_memptr(wan_client, clnt_index)->route_rule_set_v4);
+
+			if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v4 == false ||
+					get_client_memptr(wan_client, clnt_index)->ipv4_set == false)
+			{
+				continue;
+			}
+
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				memset(rt_rule, 0, size);
+				rt_rule->commit = 1;
+				rt_rule->num_rules = NUM_RULES;
+				rt_rule->ip = iptype;
+				rt_rule_entry = &rt_rule->rules[0];
+
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", clnt_index,
+						get_client_memptr(wan_client, clnt_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						clnt_index,
+						get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4);
+
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, clnt_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+				/* copy ipv4 RT rule hdl */
+				IPACMDBG_H("rt rule hdl=%x\n",
+						get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4);
+
+				rt_rule_entry->rt_rule_hdl =
+					get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4;
+
+				if (false == m_routing.ModifyRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule modify failed!\n");
+					free(rt_rule);
+					return;
+				}
+			}
+		}
+		else
+		{
+			IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", clnt_index, iptype,
+					get_client_memptr(wan_client, clnt_index)->ipv6_set,
+					get_client_memptr(wan_client, clnt_index)->route_rule_set_v6);
+
+			if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v6 == 0)
+			{
+				continue;
+			}
+
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				memset(rt_rule, 0, size);
+				rt_rule->commit = 1;
+				rt_rule->num_rules = NUM_RULES;
+				rt_rule->ip = iptype;
+				rt_rule_entry = &rt_rule->rules[0];
+
+				/* Modify only rules in v6 WAN RT TBL*/
+				for (v6_num = 0;
+						v6_num < get_client_memptr(wan_client, clnt_index)->route_rule_set_v6;
+						v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							clnt_index,
+							get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6);
+
+					/* Downlink traffic from Wan iface, directly through IPA */
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					IPACMDBG_H("rt rule hdl=%x\n",
+							get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num]);
+
+					rt_rule_entry->rt_rule_hdl =
+						get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num];
+
+					if (false == m_routing.ModifyRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule Modify failed!\n");
+						free(rt_rule);
+						return;
+					}
+				}
+			} /* end of for loop */
+		}
+
+	}
+
+	free(rt_rule);
+	return;
+}
+
+/*handle eth client */
+int IPACM_Wan::handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data)
+{
+	FILE *fp = NULL;
+
+	for (int apn_index =0; apn_index < data->apn_data_stats_list_len; apn_index++)
+	{
+		if(data->apn_data_stats_list[apn_index].mux_id == ext_prop->ext[0].mux_id)
+		{
+			IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, MUX ID %d TX (P%lu/B%lu) RX (P%lu/B%lu)\n",
+				data->apn_data_stats_list[apn_index].mux_id,
+					data->apn_data_stats_list[apn_index].num_ul_packets,
+						data->apn_data_stats_list[apn_index].num_ul_bytes,
+							data->apn_data_stats_list[apn_index].num_dl_packets,
+								data->apn_data_stats_list[apn_index].num_dl_bytes);
+			fp = fopen(IPA_NETWORK_STATS_FILE_NAME, "w");
+			if ( fp == NULL )
+			{
+				IPACMERR("Failed to write pipe stats to %s, error is %d - %s\n",
+						IPA_NETWORK_STATS_FILE_NAME, errno, strerror(errno));
+				return IPACM_FAILURE;
+			}
+
+			fprintf(fp, NETWORK_STATS,
+				dev_name,
+					data->apn_data_stats_list[apn_index].num_ul_packets,
+						data->apn_data_stats_list[apn_index].num_ul_bytes,
+							data->apn_data_stats_list[apn_index].num_dl_packets,
+								data->apn_data_stats_list[apn_index].num_dl_bytes);
+			fclose(fp);
+			break;
+		};
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::add_dummy_rx_hdr()
+{
+
+#define IFACE_INDEX_LEN 2
+	char index[IFACE_INDEX_LEN];
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+	int len = 0;
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_hdr_add *ipv6_hdr;
+	struct ethhdr *eth_ipv6;
+	struct ipa_ioc_add_hdr_proc_ctx* pHeaderProcTable = NULL;
+	uint32_t cnt;
+
+	/* get netdev-mac */
+	if(tx_prop != NULL)
+	{
+		/* copy partial header for v6 */
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+				 if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+				 {
+								IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+								memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+								memcpy(sCopyHeader.name,
+											 tx_prop->tx[cnt].hdr_name,
+											 sizeof(sCopyHeader.name));
+
+								IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+								if (m_header.CopyHeader(&sCopyHeader) == false)
+								{
+									PERROR("ioctl copy header failed");
+									return IPACM_FAILURE;
+								}
+
+								IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+								IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+								if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+								{
+									IPACMERR("header oversize\n");
+									return IPACM_FAILURE;
+								}
+								else
+								{
+									/* copy client mac_addr to partial header */
+									IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
+											sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+									/* only copy 6 bytes mac-address */
+									if(sCopyHeader.is_eth2_ofst_valid == false)
+									{
+										memcpy(netdev_mac, &sCopyHeader.hdr[0+IPA_MAC_ADDR_SIZE],
+												sizeof(netdev_mac));
+									}
+									else
+									{
+										memcpy(netdev_mac, &sCopyHeader.hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+												sizeof(netdev_mac));
+									}
+								}
+					break;
+				}
+		}
+	}
+
+	len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+	if (pHeaderDescriptor == NULL)
+	{
+		IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+		return IPACM_FAILURE;
+	}
+	ipv6_hdr = &pHeaderDescriptor->hdr[0];
+	/* copy ethernet type to header */
+	eth_ipv6 = (struct ethhdr *) (ipv6_hdr->hdr +2);
+	memcpy(eth_ipv6->h_dest, netdev_mac, ETH_ALEN);
+	memcpy(eth_ipv6->h_source, ext_router_mac_addr, ETH_ALEN);
+	eth_ipv6->h_proto = htons(ETH_P_IPV6);
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+
+	memset(ipv6_hdr->name, 0,
+			 sizeof(pHeaderDescriptor->hdr[0].name));
+
+	snprintf(index,sizeof(index), "%d", ipa_if_num);
+	strlcpy(ipv6_hdr->name, index, sizeof(ipv6_hdr->name));
+	ipv6_hdr->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+	if (strlcat(ipv6_hdr->name, IPA_DUMMY_ETH_HDR_NAME_v6, sizeof(ipv6_hdr->name)) > IPA_RESOURCE_NAME_MAX)
+	{
+		IPACMERR(" header name construction failed exceed length (%d)\n", strlen(ipv6_hdr->name));
+		return IPACM_FAILURE;
+	}
+
+	ipv6_hdr->hdr_len = ETH_HLEN + 2;
+	ipv6_hdr->hdr_hdl = -1;
+	ipv6_hdr->is_partial = 0;
+	ipv6_hdr->status = -1;
+	ipv6_hdr->type = IPA_HDR_L2_ETHERNET_II;
+
+	if (m_header.AddHeader(pHeaderDescriptor) == false ||
+			ipv6_hdr->status != 0)
+	{
+		IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", ipv6_hdr->status);
+		return IPACM_FAILURE;
+	}
+
+	hdr_hdl_dummy_v6 = ipv6_hdr->hdr_hdl;
+	IPACMDBG_H("dummy v6 full header name:%s header handle:(0x%x)\n",
+								 ipv6_hdr->name,
+								 hdr_hdl_dummy_v6);
+	/* add dummy hdr_proc_hdl */
+	len = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_add);
+	pHeaderProcTable = (ipa_ioc_add_hdr_proc_ctx*)malloc(len);
+	if(pHeaderProcTable == NULL)
+	{
+		IPACMERR("Cannot allocate header processing table.\n");
+		return IPACM_FAILURE;
+	}
+
+	memset(pHeaderProcTable, 0, len);
+	pHeaderProcTable->commit = 1;
+	pHeaderProcTable->num_proc_ctxs = 1;
+	pHeaderProcTable->proc_ctx[0].hdr_hdl = hdr_hdl_dummy_v6;
+	if (m_header.AddHeaderProcCtx(pHeaderProcTable) == false)
+	{
+		IPACMERR("Adding dummy hhdr_proc_hdl failed with status: %d\n", pHeaderProcTable->proc_ctx[0].status);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		hdr_proc_hdl_dummy_v6 = pHeaderProcTable->proc_ctx[0].proc_ctx_hdl;
+		IPACMDBG_H("dummy hhdr_proc_hdl is added successfully. (0x%x)\n", hdr_proc_hdl_dummy_v6);
+	}
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
new file mode 100644
index 0000000..3bf95f2
--- /dev/null
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -0,0 +1,2036 @@
+/*
+Copyright (c) 2013-2016, 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_Wlan.cpp
+
+@brief
+This file implements the WLAN iface functionality.
+
+@Author
+Skylar Chang
+
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Netlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_IfaceManager.h>
+#include <IPACM_ConntrackListener.h>
+
+
+/* static member to store the number of total wifi clients within all APs*/
+int IPACM_Wlan::total_num_wifi_clients = 0;
+
+int IPACM_Wlan::num_wlan_ap_iface = 0;
+
+IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index)
+{
+#define WLAN_AMPDU_DEFAULT_FILTER_RULES 3
+
+	wlan_ap_index = IPACM_Wlan::num_wlan_ap_iface;
+	if(wlan_ap_index < 0 || wlan_ap_index > 1)
+	{
+		IPACMERR("Wlan_ap_index is not correct: %d, not creating instance.\n", wlan_ap_index);
+		if (tx_prop != NULL)
+		{
+			free(tx_prop);
+		}
+		if (rx_prop != NULL)
+		{
+			free(rx_prop);
+		}
+		if (iface_query != NULL)
+		{
+			free(iface_query);
+		}
+		delete this;
+		return;
+	}
+
+	num_wifi_client = 0;
+	header_name_count = 0;
+	wlan_client = NULL;
+
+	if(iface_query != NULL)
+	{
+		wlan_client_len = (sizeof(ipa_wlan_client)) + (iface_query->num_tx_props * sizeof(wlan_client_rt_hdl));
+		wlan_client = (ipa_wlan_client *)calloc(IPA_MAX_NUM_WIFI_CLIENTS, wlan_client_len);
+		if (wlan_client == NULL)
+		{
+			IPACMERR("unable to allocate memory\n");
+			return;
+		}
+		IPACMDBG_H("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+	}
+	Nat_App = NatApp::GetInstance();
+	if (Nat_App == NULL)
+	{
+		IPACMERR("unable to get Nat App instance \n");
+		return;
+	}
+
+	IPACM_Wlan::num_wlan_ap_iface++;
+	IPACMDBG_H("Now the number of wlan AP iface is %d\n", IPACM_Wlan::num_wlan_ap_iface);
+
+	m_is_guest_ap = false;
+	if (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == INTERNET)
+	{
+		m_is_guest_ap = true;
+	}
+	IPACMDBG_H("%s: guest ap enable: %d \n",
+		IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, m_is_guest_ap);
+
+#ifdef FEATURE_IPA_ANDROID
+	/* set the IPA-client pipe enum */
+	if(ipa_if_cate == WLAN_IF)
+	{
+		handle_tethering_client(false, IPACM_CLIENT_WLAN);
+	}
+#endif
+	return;
+}
+
+
+IPACM_Wlan::~IPACM_Wlan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param)
+{
+	if(is_active == false && event != IPA_LAN_DELETE_SELF)
+	{
+		IPACMDBG_H("The interface is no longer active, return.\n");
+		return;
+	}
+
+	int ipa_interface_index;
+	int wlan_index;
+	ipacm_ext_prop* ext_prop;
+	ipacm_event_iface_up* data_wan;
+	ipacm_event_iface_up_tehter* data_wan_tether;
+
+	switch (event)
+	{
+
+	case IPA_WLAN_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
+				handle_down_evt();
+				/* reset the AP-iface category to unknown */
+				IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
+				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+				IPACM_Wlan::total_num_wifi_clients = (IPACM_Wlan::total_num_wifi_clients) - \
+                                                                     (num_wifi_client);
+				return;
+			}
+		}
+		break;
+
+	case IPA_PRIVATE_SUBNET_CHANGE_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			/* internel event: data->if_index is ipa_if_index */
+			if (data->if_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from itself posting, ignore\n");
+				return;
+			}
+			else
+			{
+				IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from other LAN iface \n");
+#ifdef FEATURE_IPA_ANDROID
+				handle_private_subnet_android(IPA_IP_v4);
+#endif
+				IPACMDBG_H(" delete old private subnet rules, use new sets \n");
+				return;
+			}
+		}
+		break;
+
+	case IPA_LAN_DELETE_SELF:
+	{
+		ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+		if(data->if_index == ipa_if_num)
+		{
+			IPACM_Wlan::num_wlan_ap_iface--;
+			IPACMDBG_H("Now the number of wlan AP iface is %d\n", IPACM_Wlan::num_wlan_ap_iface);
+
+			IPACMDBG_H("Received IPA_LAN_DELETE_SELF event.\n");
+			IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+			delete this;
+		}
+		break;
+	}
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+					 (data->iptype == IPA_IP_v6 &&
+						data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+					  data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+			{
+				IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+				return;
+			}
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				/* check v4 not setup before, v6 can have 2 iface ip */
+				if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
+				    || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+				{
+					IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+					/* Post event to NAT */
+					if (data->iptype == IPA_IP_v4)
+					{
+						ipacm_cmd_q_data evt_data;
+						ipacm_event_iface_up *info;
+
+						info = (ipacm_event_iface_up *)
+							 malloc(sizeof(ipacm_event_iface_up));
+						if (info == NULL)
+						{
+							IPACMERR("Unable to allocate memory\n");
+							return;
+						}
+
+						memcpy(info->ifname, dev_name, IF_NAME_LEN);
+						info->ipv4_addr = data->ipv4_addr;
+						info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+						evt_data.event = IPA_HANDLE_WLAN_UP;
+						evt_data.evt_data = (void *)info;
+
+						/* Insert IPA_HANDLE_WLAN_UP to command queue */
+						IPACMDBG_H("posting IPA_HANDLE_WLAN_UP for IPv4 with below information\n");
+						IPACMDBG_H("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+										 info->ipv4_addr, info->addr_mask);
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+					}
+
+					if(handle_addr_evt(data) == IPACM_FAILURE)
+					{
+						return;
+					}
+
+#ifdef FEATURE_IPA_ANDROID
+					add_dummy_private_subnet_flt_rule(data->iptype);
+					handle_private_subnet_android(data->iptype);
+#else
+					handle_private_subnet(data->iptype);
+#endif
+
+					if (IPACM_Wan::isWanUP(ipa_if_num))
+					{
+						if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
+						{
+							if(IPACM_Wan::backhaul_is_sta_mode == false)
+							{
+								ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+								IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4,
+												IPACM_Wan::getXlat_Mux_Id());
+							}
+							else
+							{
+								IPACM_Lan::handle_wan_up(IPA_IP_v4);
+							}
+						}
+					}
+
+					if(IPACM_Wan::isWanUP_V6(ipa_if_num))
+					{
+						if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
+						{
+							memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
+							install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+
+							if(IPACM_Wan::backhaul_is_sta_mode == false)
+							{
+								ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+								IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+							}
+							else
+							{
+								IPACM_Lan::handle_wan_up(IPA_IP_v6);
+							}
+						}
+					}
+
+					IPACMDBG_H("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n");
+					/* checking if SW-RT_enable */
+					if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+					{
+						/* handle software routing enable event*/
+						IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+						handle_software_routing_enable();
+					}
+				}
+			}
+		}
+		break;
+#ifdef FEATURE_IPA_ANDROID
+	case IPA_HANDLE_WAN_UP_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_TETHER event\n");
+
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+			{
+				if(data_wan_tether->is_sta == false)
+				{
+					ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+					IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+				}
+				else
+				{
+					IPACM_Lan::handle_wan_up(IPA_IP_v4);
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP_V6_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6_TETHER event\n");
+
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+			{
+				memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
+				install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
+
+				if(data_wan_tether->is_sta == false)
+				{
+					ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+					IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+				}
+				else
+				{
+					IPACM_Lan::handle_wan_up(IPA_IP_v6);
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_TETHER event\n");
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			if(data_wan_tether->is_sta == false && wlan_ap_index > 0)
+			{
+				IPACMDBG_H("This is not the first AP instance and not STA mode, ignore WAN_DOWN event.\n");
+				return;
+			}
+			if (rx_prop != NULL)
+			{
+				if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+				{
+					handle_wan_down(data_wan_tether->is_sta);
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_V6_TETHER:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER event\n");
+		data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+		if(data_wan_tether == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+					data_wan_tether->if_index_tether,
+					IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+		if (data_wan_tether->if_index_tether == ipa_if_num)
+		{
+			/* clean up v6 RT rules*/
+			IPACMDBG_H("Received IPA_WAN_V6_DOWN in WLAN-instance and need clean up client IPv6 address \n");
+			/* reset wifi-client ipv6 rt-rules */
+			handle_wlan_client_reset_rt(IPA_IP_v6);
+
+			if (rx_prop != NULL)
+			{
+				if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+				{
+					handle_wan_down_v6(data_wan_tether->is_sta);
+				}
+			}
+		}
+		break;
+#else
+	case IPA_HANDLE_WAN_UP:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+		{
+			if(data_wan->is_sta == false)
+			{
+				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+				IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4, data_wan->xlat_mux_id);
+			}
+			else
+			{
+				IPACM_Lan::handle_wan_up(IPA_IP_v4);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP_V6:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6 event\n");
+
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+		{
+			memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
+			install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+
+			if(data_wan->is_sta == false)
+			{
+				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+				IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+			}
+			else
+			{
+				IPACM_Lan::handle_wan_up(IPA_IP_v6);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+		if (rx_prop != NULL)
+		{
+			if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+			{
+				handle_wan_down(data_wan->is_sta);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN_V6:
+		IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6 event\n");
+		data_wan = (ipacm_event_iface_up*)param;
+		if(data_wan == NULL)
+		{
+			IPACMERR("No event data is found.\n");
+			return;
+		}
+		/* clean up v6 RT rules*/
+		IPACMDBG_H("Received IPA_WAN_V6_DOWN in WLAN-instance and need clean up client IPv6 address \n");
+		/* reset wifi-client ipv6 rt-rules */
+		handle_wlan_client_reset_rt(IPA_IP_v6);
+		IPACMDBG_H("Backhaul is sta mode ? %d\n", data_wan->is_sta);
+		if (rx_prop != NULL)
+		{
+			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+			{
+				handle_wan_down_v6(data_wan->is_sta);
+			}
+		}
+		break;
+#endif
+
+	case IPA_WLAN_CLIENT_ADD_EVENT_EX:
+		{
+			ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				int i;
+				for(i=0; i<data->num_of_attribs; i++)
+				{
+					if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+					{
+						eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX, data->attribs[i].u.mac_addr);
+						break;
+					}
+				}
+				IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+				handle_wlan_client_init_ex(data);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_DEL_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WLAN_CLIENT_DEL_EVENT\n");
+				eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_DEL, IPA_IP_MAX, data->mac_addr);
+				handle_wlan_client_down_evt(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_POWER_SAVE_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WLAN_CLIENT_POWER_SAVE_EVENT\n");
+				handle_wlan_client_pwrsave(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_RECOVER_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_WLAN_CLIENT_RECOVER_EVENT\n");
+
+				wlan_index = get_wlan_client_index(data->mac_addr);
+				if ((wlan_index != IPACM_INVALID_INDEX) &&
+						(get_client_memptr(wlan_client, wlan_index)->power_save_set == true))
+				{
+
+					IPACMDBG_H("change wlan client out of  power safe mode \n");
+					get_client_memptr(wlan_client, wlan_index)->power_save_set = false;
+
+					/* First add route rules and then nat rules */
+					if(get_client_memptr(wlan_client, wlan_index)->ipv4_set == true) /* for ipv4 */
+					{
+						     IPACMDBG_H("recover client index(%d):ipv4 address: 0x%x\n",
+										 wlan_index,
+										 get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+						IPACMDBG_H("Adding Route Rules\n");
+						handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v4);
+						IPACMDBG_H("Adding Nat Rules\n");
+						Nat_App->ResetPwrSaveIf(get_client_memptr(wlan_client, wlan_index)->v4_addr);
+					}
+
+					if(get_client_memptr(wlan_client, wlan_index)->ipv6_set != 0) /* for ipv6 */
+					{
+						handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v6);
+					}
+				}
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+				if (handle_wlan_client_ipaddr(data) == IPACM_FAILURE)
+				{
+					return;
+				}
+
+				handle_wlan_client_route_rule(data->mac_addr, data->iptype);
+				if (data->iptype == IPA_IP_v4)
+				{
+					/* Add NAT rules after ipv4 RT rules are set */
+					CtList->HandleNeighIpAddrAddEvt(data);
+					//Nat_App->ResetPwrSaveIf(data->ipv4_addr);
+				}
+			}
+		}
+		break;
+
+		/* handle software routing enable event, iface will update softwarerouting_act to true*/
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+		IPACM_Iface::handle_software_routing_enable();
+		break;
+
+		/* handle software routing disable event, iface will update softwarerouting_act to false*/
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+		IPACM_Iface::handle_software_routing_disable();
+		break;
+
+	case IPA_WLAN_SWITCH_TO_SCC:
+		IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+		if(ip_type == IPA_IP_MAX)
+		{
+			handle_SCC_MCC_switch(IPA_IP_v4);
+			handle_SCC_MCC_switch(IPA_IP_v6);
+		}
+		else
+		{
+			handle_SCC_MCC_switch(ip_type);
+		}
+		eth_bridge_post_event(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, IPA_IP_MAX, NULL);
+		break;
+
+	case IPA_WLAN_SWITCH_TO_MCC:
+		IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+		if(ip_type == IPA_IP_MAX)
+		{
+			handle_SCC_MCC_switch(IPA_IP_v4);
+			handle_SCC_MCC_switch(IPA_IP_v6);
+		}
+		else
+		{
+			handle_SCC_MCC_switch(ip_type);
+		}
+		eth_bridge_post_event(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, IPA_IP_MAX, NULL);
+		break;
+
+	case IPA_CRADLE_WAN_MODE_SWITCH:
+	{
+		IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+		ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+		if(wan_mode == NULL)
+		{
+			IPACMERR("Event data is empty.\n");
+			return;
+		}
+
+		if(wan_mode->cradle_wan_mode == BRIDGE)
+		{
+			handle_cradle_wan_mode_switch(true);
+		}
+		else
+		{
+			handle_cradle_wan_mode_switch(false);
+		}
+	}
+	break;
+	case IPA_CFG_CHANGE_EVENT:
+	{
+		IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT event for %s with new wlan-mode: %s old wlan-mode: %s\n",
+				IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name,
+				(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == 0) ? "full" : "internet",
+				(m_is_guest_ap == true) ? "internet" : "full");
+		/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
+		if (rx_prop != NULL || tx_prop != NULL)
+		{
+			IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+			IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+		}
+
+		if (m_is_guest_ap == true && (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == FULL))
+		{
+			m_is_guest_ap = false;
+			IPACMDBG_H("wlan mode is switched to full access mode. \n");
+			eth_bridge_handle_wlan_mode_switch();
+		}
+		else if (m_is_guest_ap == false && (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == INTERNET))
+		{
+			m_is_guest_ap = true;
+			IPACMDBG_H("wlan mode is switched to internet only access mode. \n");
+			eth_bridge_handle_wlan_mode_switch();
+		}
+		else
+		{
+			IPACMDBG_H("No change in %s access mode. \n",
+					IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+		}
+	}
+	break;
+	case IPA_TETHERING_STATS_UPDATE_EVENT:
+	{
+		IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+		if (IPACM_Wan::isWanUP(ipa_if_num) || IPACM_Wan::isWanUP_V6(ipa_if_num))
+		{
+			if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+			{
+				ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+				if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+				{
+					IPACMERR("not valid pipe stats\n");
+					return;
+				}
+				handle_tethering_stats_event(data);
+			};
+		}
+	}
+	break;
+	default:
+		break;
+	}
+	return;
+}
+
+/* handle wifi client initial,copy all partial headers (tx property) */
+int IPACM_Wlan::handle_wlan_client_init_ex(ipacm_event_data_wlan_ex *data)
+{
+
+#define WLAN_IFACE_INDEX_LEN 2
+
+	int res = IPACM_SUCCESS, len = 0, i, evt_size;
+	char index[WLAN_IFACE_INDEX_LEN];
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+        uint32_t cnt;
+
+	/* start of adding header */
+	IPACMDBG_H("Wifi client number for this iface: %d & total number of wlan clients: %d\n",
+                 num_wifi_client,IPACM_Wlan::total_num_wifi_clients);
+
+	if ((num_wifi_client >= IPA_MAX_NUM_WIFI_CLIENTS) ||
+			(IPACM_Wlan::total_num_wifi_clients >= IPA_MAX_NUM_WIFI_CLIENTS))
+	{
+		IPACMERR("Reached maximum number of wlan clients\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG_H("Wifi client number: %d\n", num_wifi_client);
+
+	/* add header to IPA */
+	if(tx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+		if (pHeaderDescriptor == NULL)
+		{
+			IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+			return IPACM_FAILURE;
+		}
+
+		evt_size = sizeof(ipacm_event_data_wlan_ex) + data->num_of_attribs * sizeof(struct ipa_wlan_hdr_attrib_val);
+		get_client_memptr(wlan_client, num_wifi_client)->p_hdr_info = (ipacm_event_data_wlan_ex*)malloc(evt_size);
+		memcpy(get_client_memptr(wlan_client, num_wifi_client)->p_hdr_info, data, evt_size);
+
+		/* copy partial header for v4*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+			{
+				IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+				memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+				memcpy(sCopyHeader.name,
+							 tx_prop->tx[cnt].hdr_name,
+							 sizeof(sCopyHeader.name));
+
+				IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+				if (m_header.CopyHeader(&sCopyHeader) == false)
+				{
+					PERROR("ioctl copy header failed");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+				if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+				{
+					IPACMERR("header oversize\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					memcpy(pHeaderDescriptor->hdr[0].hdr,
+								 sCopyHeader.hdr,
+								 sCopyHeader.hdr_len);
+				}
+
+				for(i = 0; i < data->num_of_attribs; i++)
+				{
+					if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+					{
+						memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+								data->attribs[i].u.mac_addr,
+								sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+						/* copy client mac_addr to partial header */
+						memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+									 get_client_memptr(wlan_client, num_wifi_client)->mac,
+									 IPA_MAC_ADDR_SIZE);
+						/* replace src mac to bridge mac_addr if any  */
+						if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+						{
+							memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset+IPA_MAC_ADDR_SIZE],
+									 IPACM_Iface::ipacmcfg->bridge_mac,
+									 IPA_MAC_ADDR_SIZE);
+							IPACMDBG_H("device is in bridge mode \n");
+						}
+
+					}
+					else if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+					{
+						/* copy client id to header */
+						memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+									&data->attribs[i].u.sta_id, sizeof(data->attribs[i].u.sta_id));
+					}
+					else
+					{
+						IPACMDBG_H("The attribute type is not expected!\n");
+					}
+				}
+
+				pHeaderDescriptor->commit = true;
+				pHeaderDescriptor->num_hdrs = 1;
+
+				memset(pHeaderDescriptor->hdr[0].name, 0,
+							 sizeof(pHeaderDescriptor->hdr[0].name));
+
+				snprintf(index,sizeof(index), "%d", ipa_if_num);
+				strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+				pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+				if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				snprintf(index,sizeof(index), "%d", header_name_count);
+				if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+
+				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+				pHeaderDescriptor->hdr[0].is_partial = 0;
+				pHeaderDescriptor->hdr[0].status = -1;
+
+				if (m_header.AddHeader(pHeaderDescriptor) == false ||
+						pHeaderDescriptor->hdr[0].status != 0)
+				{
+					IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+				IPACMDBG_H("client(%d) v4 full header name:%s header handle:(0x%x)\n",
+								 num_wifi_client,
+								 pHeaderDescriptor->hdr[0].name,
+								 get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v4);
+				get_client_memptr(wlan_client, num_wifi_client)->ipv4_header_set=true;
+				break;
+			}
+		}
+
+		/* copy partial header for v6*/
+		for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+			{
+				IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+				memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+				memcpy(sCopyHeader.name,
+							 tx_prop->tx[cnt].hdr_name,
+							 sizeof(sCopyHeader.name));
+
+				IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+				if (m_header.CopyHeader(&sCopyHeader) == false)
+				{
+					PERROR("ioctl copy header failed");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+				if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+				{
+					IPACMERR("header oversize\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else
+				{
+					memcpy(pHeaderDescriptor->hdr[0].hdr,
+								 sCopyHeader.hdr,
+								 sCopyHeader.hdr_len);
+				}
+
+				for(i = 0; i < data->num_of_attribs; i++)
+				{
+					if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+					{
+						memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+								data->attribs[i].u.mac_addr,
+								sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+						/* copy client mac_addr to partial header */
+						memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+								get_client_memptr(wlan_client, num_wifi_client)->mac,
+								IPA_MAC_ADDR_SIZE);
+
+						/* replace src mac to bridge mac_addr if any  */
+						if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+						{
+							memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset+IPA_MAC_ADDR_SIZE],
+									 IPACM_Iface::ipacmcfg->bridge_mac,
+									 IPA_MAC_ADDR_SIZE);
+							IPACMDBG_H("device is in bridge mode \n");
+						}
+					}
+					else if (data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+					{
+						/* copy client id to header */
+						memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+								&data->attribs[i].u.sta_id, sizeof(data->attribs[i].u.sta_id));
+					}
+					else
+					{
+						IPACMDBG_H("The attribute type is not expected!\n");
+					}
+				}
+
+				pHeaderDescriptor->commit = true;
+				pHeaderDescriptor->num_hdrs = 1;
+
+				memset(pHeaderDescriptor->hdr[0].name, 0,
+							 sizeof(pHeaderDescriptor->hdr[0].name));
+
+				snprintf(index,sizeof(index), "%d", ipa_if_num);
+				strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+				pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+				if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				snprintf(index,sizeof(index), "%d", header_name_count);
+				if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+				{
+					IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+				pHeaderDescriptor->hdr[0].is_partial = 0;
+				pHeaderDescriptor->hdr[0].status = -1;
+
+				if (m_header.AddHeader(pHeaderDescriptor) == false ||
+						pHeaderDescriptor->hdr[0].status != 0)
+				{
+					IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+
+				get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+				IPACMDBG_H("client(%d) v6 full header name:%s header handle:(0x%x)\n",
+								 num_wifi_client,
+								 pHeaderDescriptor->hdr[0].name,
+											 get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v6);
+
+				get_client_memptr(wlan_client, num_wifi_client)->ipv6_header_set=true;
+				break;
+			}
+		}
+
+		/* initialize wifi client*/
+		get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v4 = false;
+		get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v6 = 0;
+		get_client_memptr(wlan_client, num_wifi_client)->ipv4_set = false;
+		get_client_memptr(wlan_client, num_wifi_client)->ipv6_set = 0;
+		get_client_memptr(wlan_client, num_wifi_client)->power_save_set=false;
+		num_wifi_client++;
+		header_name_count++; //keep increasing header_name_count
+		IPACM_Wlan::total_num_wifi_clients++;
+		res = IPACM_SUCCESS;
+		IPACMDBG_H("Wifi client number: %d\n", num_wifi_client);
+	}
+	else
+	{
+		return res;
+	}
+
+fail:
+	free(pHeaderDescriptor);
+	return res;
+}
+
+/*handle wifi client */
+int IPACM_Wlan::handle_wlan_client_ipaddr(ipacm_event_data_all *data)
+{
+	int clnt_indx;
+	int v6_num;
+	uint32_t ipv6_link_local_prefix = 0xFE800000;
+	uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
+
+	IPACMDBG_H("number of wifi clients: %d\n", num_wifi_client);
+	IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 data->mac_addr[0],
+					 data->mac_addr[1],
+					 data->mac_addr[2],
+					 data->mac_addr[3],
+					 data->mac_addr[4],
+					 data->mac_addr[5]);
+
+	clnt_indx = get_wlan_client_index(data->mac_addr);
+
+		if (clnt_indx == IPACM_INVALID_INDEX)
+		{
+			IPACMERR("wlan client not found/attached \n");
+			return IPACM_FAILURE;
+		}
+
+	IPACMDBG_H("Ip-type received %d\n", data->iptype);
+	if (data->iptype == IPA_IP_v4)
+	{
+		IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+		if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+		{
+			if (get_client_memptr(wlan_client, clnt_indx)->ipv4_set == false)
+			{
+				get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				get_client_memptr(wlan_client, clnt_indx)->ipv4_set = true;
+			}
+			else
+			{
+			   /* check if client got new IPv4 address*/
+			   if(data->ipv4_addr == get_client_memptr(wlan_client, clnt_indx)->v4_addr)
+			   {
+			     IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+				 return IPACM_FAILURE;
+			   }
+			   else
+			   {
+			     IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+				 /* delete NAT rules first */
+				 CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clnt_indx)->v4_addr);
+			     delete_default_qos_rtrules(clnt_indx,IPA_IP_v4);
+		         get_client_memptr(wlan_client, clnt_indx)->route_rule_set_v4 = false;
+			     get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+			}
+		}
+	}
+	else
+	{
+		    IPACMDBG_H("Invalid client IPv4 address \n");
+		    return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+		{
+			IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+				memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+			{
+				IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+				return IPACM_FAILURE;
+			}
+
+			if(get_client_memptr(wlan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+			{
+
+		       for(v6_num=0;v6_num < get_client_memptr(wlan_client, clnt_indx)->ipv6_set;v6_num++)
+				{
+					if( data->ipv6_addr[0] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][0] &&
+			           data->ipv6_addr[1] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][1] &&
+			  	        data->ipv6_addr[2]== get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][2] &&
+			  	         data->ipv6_addr[3] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][3])
+					{
+			  	    IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
+			  	    return IPACM_FAILURE; /* not setup the RT rules*/
+			  		break;
+					}
+				}
+
+		       /* not see this ipv6 before for wifi client*/
+			   get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+			   get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+			   get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+			   get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+			   get_client_memptr(wlan_client, clnt_indx)->ipv6_set++;
+		    }
+		    else
+		    {
+				IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+				return IPACM_FAILURE; /* not setup the RT rules*/
+		    }
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wifi client routing rule*/
+int IPACM_Wlan::handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	uint32_t tx_index;
+	int wlan_index,v6_num;
+	const int NUM = 1;
+
+	if(tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+			mac_addr[0], mac_addr[1], mac_addr[2],
+			mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	wlan_index = get_wlan_client_index(mac_addr);
+	if (wlan_index == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("wlan client not found/attached \n");
+		return IPACM_SUCCESS;
+	}
+
+	/* during power_save mode, even receive IP_ADDR_ADD, not setting RT rules*/
+	if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true)
+	{
+		IPACMDBG_H("wlan client is in power safe mode \n");
+		return IPACM_SUCCESS;
+	}
+
+	if (iptype==IPA_IP_v4)
+	{
+		IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
+				get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+				get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+	}
+	else
+	{
+		IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+				get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+				get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+	}
+
+
+	/* Add default  Qos routing rules if not set yet */
+	if ((iptype == IPA_IP_v4
+				&& get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
+				&& get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
+			|| (iptype == IPA_IP_v6
+				&& get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 < get_client_memptr(wlan_client, wlan_index)->ipv6_set
+			   ))
+	{
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_add));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = (uint8_t)NUM;
+		rt_rule->ip = iptype;
+
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+
+			if(iptype != tx_prop->tx[tx_index].ip)
+			{
+				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+						tx_index, tx_prop->tx[tx_index].ip,iptype);
+				continue;
+			}
+
+			rt_rule_entry = &rt_rule->rules[0];
+			rt_rule_entry->at_rear = 0;
+
+			if (iptype == IPA_IP_v4)
+			{
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+				strlcpy(rt_rule->rt_tbl_name,
+						IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+						sizeof(rt_rule->rt_tbl_name));
+				rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+				if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+				rt_rule_entry->rule.hashable = false;
+#endif
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule addition failed!\n");
+					free(rt_rule);
+					return IPACM_FAILURE;
+				}
+
+				/* copy ipv4 RT hdl */
+				get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+					rt_rule->rules[0].rt_rule_hdl;
+				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+			}
+			else
+			{
+				for(v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wlan_index,
+							get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+					/* v6 LAN_RT_TBL */
+					strlcpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+					rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+					/* Support QCMAP LAN traffic feature, send to A5 */
+					rt_rule_entry->rule.dst = iface_query->excp_pipe;
+					memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = 0;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+					rt_rule_entry->rule.hashable = true;
+#endif
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num], iptype);
+
+					/*Copy same rule to v6 WAN RT TBL*/
+					strlcpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+					rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+					/* Downlink traffic from Wan iface, directly through IPA */
+					if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+					rt_rule_entry->rule.hashable = true;
+#endif
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num], iptype);
+				}
+			}
+
+		} /* end of for loop */
+
+		free(rt_rule);
+
+		if (iptype == IPA_IP_v4)
+		{
+			get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 = true;
+		}
+		else
+		{
+			get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 = get_client_memptr(wlan_client, wlan_index)->ipv6_set;
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wifi client power-save mode*/
+int IPACM_Wlan::handle_wlan_client_pwrsave(uint8_t *mac_addr)
+{
+	int clt_indx;
+	IPACMDBG_H("wlan->handle_wlan_client_pwrsave();\n");
+
+	clt_indx = get_wlan_client_index(mac_addr);
+	if (clt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("wlan client not attached\n");
+		return IPACM_SUCCESS;
+	}
+
+        if (get_client_memptr(wlan_client, clt_indx)->power_save_set == false)
+	{
+		/* First reset nat rules and then route rules */
+	    if(get_client_memptr(wlan_client, clt_indx)->ipv4_set == true)
+	    {
+			IPACMDBG_H("Deleting Nat Rules\n");
+			Nat_App->UpdatePwrSaveIf(get_client_memptr(wlan_client, clt_indx)->v4_addr);
+ 	     }
+
+		IPACMDBG_H("Deleting default qos Route Rules\n");
+		delete_default_qos_rtrules(clt_indx, IPA_IP_v4);
+		delete_default_qos_rtrules(clt_indx, IPA_IP_v6);
+                get_client_memptr(wlan_client, clt_indx)->power_save_set = true;
+	}
+	else
+	{
+		IPACMDBG_H("wlan client already in power-save mode\n");
+	}
+    return IPACM_SUCCESS;
+}
+
+/*handle wifi client del mode*/
+int IPACM_Wlan::handle_wlan_client_down_evt(uint8_t *mac_addr)
+{
+	int clt_indx;
+	uint32_t tx_index;
+	int num_wifi_client_tmp = num_wifi_client;
+	int num_v6;
+
+	IPACMDBG_H("total client: %d\n", num_wifi_client_tmp);
+
+	clt_indx = get_wlan_client_index(mac_addr);
+	if (clt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG_H("wlan client not attached\n");
+		return IPACM_SUCCESS;
+	}
+
+	/* First reset nat rules and then route rules */
+	if(get_client_memptr(wlan_client, clt_indx)->ipv4_set == true)
+	{
+	        IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, clt_indx)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clt_indx)->v4_addr);
+ 	}
+
+	if (delete_default_qos_rtrules(clt_indx, IPA_IP_v4))
+	{
+		IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", clt_indx);
+		return IPACM_FAILURE;
+	}
+
+	if (delete_default_qos_rtrules(clt_indx, IPA_IP_v6))
+	{
+		IPACMERR("unbale to delete v6 default qos route rules for indexn: %d\n", clt_indx);
+		return IPACM_FAILURE;
+	}
+
+	/* Delete wlan client header */
+	if(get_client_memptr(wlan_client, clt_indx)->ipv4_header_set == true)
+	{
+	if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v4)
+			== false)
+	{
+		return IPACM_FAILURE;
+	}
+		get_client_memptr(wlan_client, clt_indx)->ipv4_header_set = false;
+	}
+
+	if(get_client_memptr(wlan_client, clt_indx)->ipv6_header_set == true)
+	{
+	if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v6)
+			== false)
+	{
+		return IPACM_FAILURE;
+	}
+		get_client_memptr(wlan_client, clt_indx)->ipv6_header_set = false;
+	}
+
+	/* Reset ip_set to 0*/
+	get_client_memptr(wlan_client, clt_indx)->ipv4_set = false;
+	get_client_memptr(wlan_client, clt_indx)->ipv6_set = 0;
+	get_client_memptr(wlan_client, clt_indx)->ipv4_header_set = false;
+	get_client_memptr(wlan_client, clt_indx)->ipv6_header_set = false;
+	get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+	get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = 0;
+	free(get_client_memptr(wlan_client, clt_indx)->p_hdr_info);
+
+	for (; clt_indx < num_wifi_client_tmp - 1; clt_indx++)
+	{
+		get_client_memptr(wlan_client, clt_indx)->p_hdr_info = get_client_memptr(wlan_client, (clt_indx + 1))->p_hdr_info;
+
+		memcpy(get_client_memptr(wlan_client, clt_indx)->mac,
+					 get_client_memptr(wlan_client, (clt_indx + 1))->mac,
+					 sizeof(get_client_memptr(wlan_client, clt_indx)->mac));
+
+		get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl_v4;
+		get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl_v6;
+		get_client_memptr(wlan_client, clt_indx)->v4_addr = get_client_memptr(wlan_client, (clt_indx + 1))->v4_addr;
+
+		get_client_memptr(wlan_client, clt_indx)->ipv4_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_set;
+		get_client_memptr(wlan_client, clt_indx)->ipv6_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_set;
+		get_client_memptr(wlan_client, clt_indx)->ipv4_header_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_header_set;
+		get_client_memptr(wlan_client, clt_indx)->ipv6_header_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_header_set;
+
+		get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v4;
+		get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v6;
+
+                for(num_v6=0;num_v6< get_client_memptr(wlan_client, clt_indx)->ipv6_set;num_v6++)
+	        {
+		    get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][0] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][0];
+		    get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][1] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][1];
+		    get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][2] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][2];
+		    get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][3] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][3];
+                }
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+				 get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+			for(num_v6=0;num_v6< get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6;num_v6++)
+			{
+			  get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6] =
+			   	 get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6];
+			  get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6] =
+			   	 get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6];
+		    }
+		}
+	}
+
+	IPACMDBG_H(" %d wifi client deleted successfully \n", num_wifi_client);
+	num_wifi_client = num_wifi_client - 1;
+	IPACM_Wlan::total_num_wifi_clients = IPACM_Wlan::total_num_wifi_clients - 1;
+	IPACMDBG_H(" Number of wifi client: %d\n", num_wifi_client);
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wlan iface down event*/
+int IPACM_Wlan::handle_down_evt()
+{
+	int res = IPACM_SUCCESS, i, num_private_subnet_fl_rule;
+
+	IPACMDBG_H("WLAN ip-type: %d \n", ip_type);
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		IPACMERR("Invalid iptype: 0x%x\n", ip_type);
+		goto fail;
+	}
+
+	/* delete wan filter rule */
+	if (IPACM_Wan::isWanUP(ipa_if_num) && rx_prop != NULL)
+	{
+		IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+		IPACM_Lan::handle_wan_down(IPACM_Wan::backhaul_is_sta_mode);
+	}
+
+	if (IPACM_Wan::isWanUP_V6(ipa_if_num) && rx_prop != NULL)
+	{
+		IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+		handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
+	}
+	IPACMDBG_H("finished deleting wan filtering rules\n ");
+
+	/* Delete v4 filtering rules */
+	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+	{
+		/* delete IPv4 icmp filter rules */
+		if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
+
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Deleting Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+		IPACMDBG_H("Deleted default v4 filter rules successfully.\n");
+
+		/* delete private-ipv4 filter rules */
+#ifdef FEATURE_IPA_ANDROID
+		if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES) == false)
+		{
+			IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+#else
+		num_private_subnet_fl_rule = IPACM_Iface::ipacmcfg->ipa_num_private_subnet > IPA_MAX_PRIVATE_SUBNET_ENTRIES?
+			IPA_MAX_PRIVATE_SUBNET_ENTRIES : IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+		if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, num_private_subnet_fl_rule) == false)
+		{
+			IPACMERR("Error deleting private subnet flt rules, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_private_subnet_fl_rule);
+#endif
+		IPACMDBG_H("Deleted private subnet v4 filter rules successfully.\n");
+	}
+
+	/* Delete v6 filtering rules */
+	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+	{
+		/* delete icmp filter rules */
+		if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+		IPACMDBG_H("Deleted default v6 filter rules successfully.\n");
+	}
+	IPACMDBG_H("finished delete filtering rules\n ");
+
+	/* Delete default v4 RT rule */
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG_H("Delete default v4 routing rules\n");
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+				== false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* Delete default v6 RT rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		IPACMDBG_H("Delete default v6 routing rules\n");
+		/* May have multiple ipv6 iface-RT rules */
+		for (i = 0; i < 2*num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+	IPACMDBG_H("finished deleting default RT rules\n ");
+
+	eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL);
+
+	/* free the wlan clients cache */
+	IPACMDBG_H("Free wlan clients cache\n");
+
+	/* Delete private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+		IPACMDBG_H(" Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		if(IPACM_Iface::ipacmcfg->DelPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+		{
+			IPACMERR(" can't Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+		}
+	}
+	/* reset the IPA-client pipe enum */
+	handle_tethering_client(true, IPACM_CLIENT_WLAN);
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+fail:
+	/* clean wifi-client header, routing rules */
+	/* clean wifi client rule*/
+	IPACMDBG_H("left %d wifi clients need to be deleted \n ", num_wifi_client);
+	for (i = 0; i < num_wifi_client; i++)
+	{
+		/* First reset nat rules and then route rules */
+		if(get_client_memptr(wlan_client, i)->ipv4_set == true)
+		{
+	        IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, i)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, i)->v4_addr);
+		}
+
+		if (delete_default_qos_rtrules(i, IPA_IP_v4))
+		{
+			IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", i);
+			res = IPACM_FAILURE;
+		}
+
+		if (delete_default_qos_rtrules(i, IPA_IP_v6))
+		{
+			IPACMERR("unbale to delete v6 default qos route rules for index: %d\n", i);
+			res = IPACM_FAILURE;
+		}
+
+		IPACMDBG_H("Delete %d client header\n", num_wifi_client);
+
+		if(get_client_memptr(wlan_client, i)->ipv4_header_set == true)
+		{
+			if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl_v4)
+				== false)
+			{
+				res = IPACM_FAILURE;
+			}
+		}
+
+		if(get_client_memptr(wlan_client, i)->ipv6_header_set == true)
+		{
+			if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl_v6)
+					== false)
+			{
+				res = IPACM_FAILURE;
+			}
+		}
+	} /* end of for loop */
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true && rx_prop != NULL )
+	{
+		IPACMDBG_H("Delete sw routing filtering rules\n");
+		IPACM_Iface::handle_software_routing_disable();
+	}
+	IPACMDBG_H("finished delete software-routing filtering rules\n ");
+
+	/* Delete corresponding ipa_rm_resource_name of RX-endpoint after delete all IPV4V6 FT-rule */
+	if (rx_prop != NULL)
+	{
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+		IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+		free(rx_prop);
+	}
+
+	for (i = 0; i < num_wifi_client; i++)
+	{
+		if(get_client_memptr(wlan_client, i)->p_hdr_info != NULL)
+		{
+			free(get_client_memptr(wlan_client, i)->p_hdr_info);
+		}
+	}
+	if(wlan_client != NULL)
+	{
+		free(wlan_client);
+	}
+	if (tx_prop != NULL)
+	{
+		free(tx_prop);
+	}
+
+	if (iface_query != NULL)
+	{
+		free(iface_query);
+	}
+
+	is_active = false;
+	post_del_self_evt();
+
+	return res;
+}
+
+/*handle reset wifi-client rt-rules */
+int IPACM_Wlan::handle_wlan_client_reset_rt(ipa_ip_type iptype)
+{
+	int i, res = IPACM_SUCCESS;
+
+	/* clean wifi-client routing rules */
+	IPACMDBG_H("left %d wifi clients to reset ip-type(%d) rules \n ", num_wifi_client, iptype);
+
+	for (i = 0; i < num_wifi_client; i++)
+	{
+		/* Reset RT rules */
+		res = delete_default_qos_rtrules(i, iptype);
+		if (res != IPACM_SUCCESS)
+		{
+			IPACMERR("Failed to delete old iptype(%d) rules.\n", iptype);
+			return res;
+		}
+
+		/* Reset ip-address */
+		if(iptype == IPA_IP_v4)
+		{
+			get_client_memptr(wlan_client, i)->ipv4_set = false;
+		}
+		else
+		{
+			get_client_memptr(wlan_client, i)->ipv6_set = 0;
+		}
+	} /* end of for loop */
+	return res;
+}
+
+void IPACM_Wlan::handle_SCC_MCC_switch(ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	uint32_t tx_index;
+	int wlan_index, v6_num;
+	const int NUM = 1;
+	int num_wifi_client_tmp = IPACM_Wlan::num_wifi_client;
+	bool isAdded = false;
+
+	if (tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return;
+	}
+
+	if (rt_rule == NULL)
+	{
+		rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_mdfy_rt_rule memory...\n");
+			return;
+		}
+
+		rt_rule->commit = 0;
+		rt_rule->num_rules = NUM;
+		rt_rule->ip = iptype;
+	}
+	rt_rule_entry = &rt_rule->rules[0];
+
+	/* modify ipv4 routing rule */
+	if (iptype == IPA_IP_v4)
+	{
+		for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+		{
+			IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n",
+					wlan_index, iptype,
+					get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+
+			if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false)
+			{
+				IPACMDBG_H("client %d route rules not set\n", wlan_index);
+				continue;
+			}
+
+			IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d ignore\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4;
+
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+
+				rt_rule_entry->rt_rule_hdl =
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+				if (false == m_routing.ModifyRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule modify failed!\n");
+					free(rt_rule);
+					return;
+				}
+				isAdded = true;
+			}
+
+		}
+	}
+
+	/* modify ipv6 routing rule */
+	if (iptype == IPA_IP_v6)
+	{
+		for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+		{
+
+			IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+					get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+
+			if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+					(get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 <
+					 get_client_memptr(wlan_client, wlan_index)->ipv6_set) )
+			{
+				IPACMDBG_H("client %d route rules not set\n", wlan_index);
+				continue;
+			}
+
+			IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				for (v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;
+						v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;
+						v6_num++)
+				{
+
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wlan_index,
+							get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					rt_rule_entry->rt_rule_hdl =
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num];
+
+					if (false == m_routing.ModifyRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule modify failed!\n");
+						free(rt_rule);
+						return;
+					}
+					isAdded = true;
+				}
+			}
+
+		}
+	}
+
+
+	if (isAdded)
+	{
+		if (false == m_routing.Commit(iptype))
+		{
+			IPACMERR("Routing rule modify commit failed!\n");
+			free(rt_rule);
+			return;
+		}
+
+		IPACMDBG("Routing rule modified successfully \n");
+	}
+
+	if(rt_rule)
+	{
+		free(rt_rule);
+	}
+	return;
+}
+
+void IPACM_Wlan::eth_bridge_handle_wlan_mode_switch()
+{
+	int i;
+
+	/* ====== post events to mimic WLAN interface goes down/up when AP mode is changing ====== */
+
+	/* first post IFACE_DOWN event */
+	eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL);
+
+	/* then post IFACE_UP event */
+	if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+	{
+		eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v4, NULL);
+	}
+	if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+	{
+		eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v6, NULL);
+	}
+
+	/* at last post CLIENT_ADD event */
+	for(i = 0; i < num_wifi_client; i++)
+	{
+		eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX,
+			get_client_memptr(wlan_client, i)->mac);
+	}
+
+	return;
+}
+
+bool IPACM_Wlan::is_guest_ap()
+{
+	return m_is_guest_ap;
+}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
new file mode 100644
index 0000000..073dc98
--- /dev/null
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -0,0 +1,1176 @@
+/*
+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_Xml.cpp
+
+  @brief
+   This file implements the XML specific parsing functionality.
+
+  @Author
+   Skylar Chang/Shihuan Liu
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Netlink.h"
+
+static char* IPACM_read_content_element
+(
+	 xmlNode* element
+);
+
+static int32_t IPACM_util_icmp_string
+(
+	 const char* xml_str,
+	 const char* str
+);
+
+static int ipacm_cfg_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_conf_t *config
+);
+
+static int IPACM_firewall_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_firewall_conf_t *config
+);
+
+/*Reads content (stored as child) of the element */
+static char* IPACM_read_content_element
+(
+	 xmlNode* element
+)
+{
+	xmlNode* child_ptr;
+
+	for (child_ptr  = element->children;
+			 child_ptr != NULL;
+			 child_ptr  = child_ptr->next)
+	{
+		if (child_ptr->type == XML_TEXT_NODE)
+		{
+			return (char*)child_ptr->content;
+		}
+	}
+	return NULL;
+}
+
+/* insensitive comparison of a libxml's string (xml_str) and a regular string (str)*/
+static int32_t IPACM_util_icmp_string
+(
+	 const char* xml_str,
+	 const char* str
+)
+{
+	int32_t ret = -1;
+
+	if (NULL != xml_str && NULL != str)
+	{
+		uint32_t len1 = strlen(str);
+		uint32_t len2 = strlen(xml_str);
+		/* If the lengths match, do the string comparison */
+		if (len1 == len2)
+		{
+			ret = strncasecmp(xml_str, str, len1);
+		}
+	}
+
+	return ret;
+}
+
+/* This function read IPACM XML and populate the IPA CM Cfg */
+int ipacm_read_cfg_xml(char *xml_file, IPACM_conf_t *config)
+{
+	xmlDocPtr doc = NULL;
+	xmlNode* root = NULL;
+	int ret_val = IPACM_SUCCESS;
+
+	/* Invoke the XML parser and obtain the parse tree */
+	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+	if (doc == NULL) {
+		IPACMDBG_H("IPACM_xml_parse: libxml returned parse error!\n");
+		return IPACM_FAILURE;
+	}
+
+	/*Get the root of the tree*/
+	root = xmlDocGetRootElement(doc);
+
+	memset(config, 0, sizeof(IPACM_conf_t));
+
+	/* parse the xml tree returned by libxml */
+	ret_val = ipacm_cfg_xml_parse_tree(root, config);
+
+	if (ret_val != IPACM_SUCCESS)
+	{
+		IPACMDBG_H("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
+	}
+
+	/* Free up the libxml's parse tree */
+	xmlFreeDoc(doc);
+
+	return ret_val;
+}
+
+/* This function traverses the xml tree*/
+static int ipacm_cfg_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_conf_t *config
+)
+{
+	int32_t ret_val = IPACM_SUCCESS;
+	int str_size;
+	char* content;
+	char content_buf[MAX_XML_STR_LEN];
+
+	if (NULL == xml_node)
+		return ret_val;
+	while ( xml_node != NULL &&
+				 ret_val == IPACM_SUCCESS)
+	{
+		switch (xml_node->type)
+		{
+		case XML_ELEMENT_NODE:
+			{
+				if (IPACM_util_icmp_string((char*)xml_node->name, system_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, ODU_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMCFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMIFACECFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IFACE_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMPRIVATESUBNETCFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, SUBNET_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMALG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, ALG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMNat_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IP_PassthroughFlag_TAG) == 0)
+				{
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, IFACE_TAG))
+					{
+						/* increase iface entry number */
+						config->iface_config.num_iface_entries++;
+					}
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, SUBNET_TAG))
+					{
+						/* increase iface entry number */
+						config->private_subnet_config.num_subnet_entries++;
+					}
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, ALG_TAG))
+					{
+						/* increase iface entry number */
+						config->alg_config.num_alg_entries++;
+					}
+					/* go to child */
+					ret_val = ipacm_cfg_xml_parse_tree(xml_node->children, config);
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, IP_PassthroughMode_TAG) == 0)
+				{
+					IPACMDBG_H("inside IP Passthrough\n");
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (atoi(content_buf))
+						{
+							config->ip_passthrough_mode = true;
+							IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+						}
+						else
+						{
+							config->ip_passthrough_mode = false;
+							IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, ODUMODE_TAG) == 0)
+				{
+					IPACMDBG_H("inside ODU-XML\n");
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (0 == strncasecmp(content_buf, ODU_ROUTER_TAG, str_size))
+						{
+							config->router_mode_enable = true;
+							IPACMDBG_H("router-mode enable %d\n", config->router_mode_enable);
+						}
+						else if (0 == strncasecmp(content_buf, ODU_BRIDGE_TAG, str_size))
+						{
+							config->router_mode_enable = false;
+							IPACMDBG_H("router-mode enable %d\n", config->router_mode_enable);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, ODUEMBMS_OFFLOAD_TAG) == 0)
+				{
+					IPACMDBG_H("inside ODU-XML\n");
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (atoi(content_buf))
+						{
+							config->odu_embms_enable = true;
+							IPACMDBG_H("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+						}
+						else
+						{
+							config->odu_embms_enable = false;
+							IPACMDBG_H("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, NAME_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						strlcpy(config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name, content_buf, str_size+1);
+						IPACMDBG_H("Name %s\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, CATEGORY_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (0 == strncasecmp(content_buf, WANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WAN_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else if (0 == strncasecmp(content_buf, LANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = LAN_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else if (0 == strncasecmp(content_buf, WLANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WLAN_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else  if (0 == strncasecmp(content_buf, VIRTUALIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = VIRTUAL_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else  if (0 == strncasecmp(content_buf, UNKNOWNIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = UNKNOWN_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else  if (0 == strncasecmp(content_buf, ETHIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = ETH_IF;
+							IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else  if (0 == strncasecmp(content_buf, ODUIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = ODU_IF;
+							IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, MODE_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (0 == strncasecmp(content_buf, IFACE_ROUTER_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = ROUTER;
+							IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+						}
+						else  if (0 == strncasecmp(content_buf, IFACE_BRIDGE_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = BRIDGE;
+							IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, WLAN_MODE_TAG) == 0)
+				{
+					IPACMDBG_H("Inside WLAN-XML\n");
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+
+						if (0 == strncasecmp(content_buf, WLAN_FULL_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode = FULL;
+							IPACMDBG_H("Wlan-mode full(%d)\n",
+									config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode);
+						}
+						else  if (0 == strncasecmp(content_buf, WLAN_INTERNET_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode = INTERNET;
+							config->num_wlan_guest_ap++;
+							IPACMDBG_H("Wlan-mode internet(%d)\n",
+									config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, SUBNETADDRESS_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG_H("subnet_addr: %s \n", content_buf);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, SUBNETMASK_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_mask
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG_H("subnet_mask: %s \n", content_buf);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, Protocol_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+
+						if (0 == strncasecmp(content_buf, TCP_PROTOCOL_TAG, str_size))
+						{
+							config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_TCP;
+							IPACMDBG_H("Protocol %s: %d\n",
+									content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+						}
+						else if (0 == strncasecmp(content_buf, UDP_PROTOCOL_TAG, str_size))
+						{
+							config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_UDP;
+							IPACMDBG_H("Protocol %s: %d\n",
+									content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, Port_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port
+							 = atoi(content_buf);
+						IPACMDBG_H("port %d\n", config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, NAT_MaxEntries_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->nat_max_entries = atoi(content_buf);
+						IPACMDBG_H("Nat Table Max Entries %d\n", config->nat_max_entries);
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		/* go to sibling */
+		xml_node = xml_node->next;
+	} /* end while */
+	return ret_val;
+}
+
+/* This function read QCMAP CM Firewall XML and populate the QCMAP CM Cfg */
+int IPACM_read_firewall_xml(char *xml_file, IPACM_firewall_conf_t *config)
+{
+	xmlDocPtr doc = NULL;
+	xmlNode* root = NULL;
+	int ret_val;
+
+	IPACM_ASSERT(xml_file != NULL);
+	IPACM_ASSERT(config != NULL);
+
+	/* invoke the XML parser and obtain the parse tree */
+	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+	if (doc == NULL) {
+		IPACMDBG_H("IPACM_xml_parse: libxml returned parse error\n");
+		return IPACM_FAILURE;
+	}
+	/*get the root of the tree*/
+	root = xmlDocGetRootElement(doc);
+
+	/* parse the xml tree returned by libxml*/
+	ret_val = IPACM_firewall_xml_parse_tree(root, config);
+
+	if (ret_val != IPACM_SUCCESS)
+	{
+		IPACMDBG_H("IPACM_xml_parse: ipacm_firewall_xml_parse_tree returned parse error!\n");
+	}
+
+	/* free the tree */
+	xmlFreeDoc(doc);
+
+	return ret_val;
+}
+
+
+/* This function traverses the firewall xml tree */
+static int IPACM_firewall_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_firewall_conf_t *config
+)
+{
+	int mask_value_v6, mask_index;
+	int32_t ret_val = IPACM_SUCCESS;
+	char *content;
+	int str_size;
+	char content_buf[MAX_XML_STR_LEN];
+	struct in6_addr ip6_addr;
+
+	IPACM_ASSERT(config != NULL);
+
+	if (NULL == xml_node)
+		return ret_val;
+
+	while ( xml_node != NULL &&
+				 ret_val == IPACM_SUCCESS)
+	{
+		switch (xml_node->type)
+		{
+
+		case XML_ELEMENT_NODE:
+			{
+				if (0 == IPACM_util_icmp_string((char*)xml_node->name, system_TAG) ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name, MobileAPFirewallCfg_TAG) ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name, Firewall_TAG) ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallEnabled_TAG)  ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallPktsAllowed_TAG))
+				{
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, Firewall_TAG))
+					{
+						/* increase firewall entry num */
+						config->num_extd_firewall_entries++;
+					}
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallPktsAllowed_TAG))
+					{
+						/* setup action of matched rules */
+					    content = IPACM_read_content_element(xml_node);
+					    if (content)
+					    {
+						        str_size = strlen(content);
+						        memset(content_buf, 0, sizeof(content_buf));
+						        memcpy(content_buf, (void *)content, str_size);
+							if (atoi(content_buf)==1)
+							{
+								config->rule_action_accept = true;
+							}
+							else
+							{
+								config->rule_action_accept = false;
+							}
+							IPACMDBG_H(" Allow traffic which matches rules ?:%d\n",config->rule_action_accept);
+					    }
+				        }
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallEnabled_TAG))
+					{
+						/* setup if firewall enable or not */
+					    content = IPACM_read_content_element(xml_node);
+					    if (content)
+					    {
+						        str_size = strlen(content);
+						        memset(content_buf, 0, sizeof(content_buf));
+						        memcpy(content_buf, (void *)content, str_size);
+							if (atoi(content_buf)==1)
+							{
+								config->firewall_enable = true;
+							}
+						        else
+							{
+								config->firewall_enable = false;
+							}
+							IPACMDBG_H(" Firewall Enable?:%d\n", config->firewall_enable);
+				            }
+					}
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPFamily_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn
+							 = (firewall_ip_version_enum)atoi(content_buf);
+						IPACMDBG_H("\n IP family type is %d \n",
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4SourceAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4SourceIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG_H("IPv4 source address is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4SourceSubnetMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr_mask
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG_H("IPv4 source subnet mask is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4DestinationAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4DestinationIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG_H("IPv4 destination address is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4DestinationSubnetMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						content_buf[MAX_XML_STR_LEN-1] = '\0';
+						if (content_buf > 0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask
+								 = ntohl(inet_addr(content_buf));
+							IPACMDBG_H("IPv4 destination subnet mask is: %s \n", content_buf);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4TypeOfService_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TOS;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TOSValue_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+							 = atoi(content_buf);
+						IPACMDBG_H("\n IPV4 TOS val is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TOSMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+							 &= atoi(content_buf);
+						IPACMDBG_H("\n IPv4 TOS mask is %d \n",
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4NextHeaderProtocol_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol = atoi(content_buf);
+						IPACMDBG_H("\n IPv4 next header prot is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6SourceAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+						 IPA_FLT_SRC_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6SourceIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						inet_pton(AF_INET6, content_buf, &ip6_addr);
+						memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr,
+									 ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[1]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[1]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[2]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[2]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[3]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[3]);
+
+						IPACMDBG_H("\n ipv6 source addr is %d \n ",
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6SourcePrefix_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						mask_value_v6 = atoi(content_buf);
+						for (mask_index = 0; mask_index < 4; mask_index++)
+						{
+							if (mask_value_v6 >= 32)
+							{
+								mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+								mask_value_v6 -= 32;
+							}
+							else
+							{
+								mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+								mask_value_v6 = 0;
+							}
+						}
+						IPACMDBG_H("\n ipv6 source prefix is %d \n", atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6DestinationAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+						 IPA_FLT_DST_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6DestinationIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						inet_pton(AF_INET6, content_buf, &ip6_addr);
+						memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr,
+									 ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[1]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[1]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[2]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[2]);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[3]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[3]);
+						IPACMDBG_H("\n ipv6 dest addr is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6DestinationPrefix_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						mask_value_v6 = atoi(content_buf);
+						for (mask_index = 0; mask_index < 4; mask_index++)
+						{
+							if (mask_value_v6 >= 32)
+							{
+								mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+								mask_value_v6 -= 32;
+							}
+							else
+							{
+								mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+								mask_value_v6 = 0;
+							}
+						}
+						IPACMDBG_H("\n ipv6 dest prefix is %d \n", atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6TrafficClass_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TC;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TrfClsValue_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+							 = atoi(content_buf);
+						IPACMDBG_H("\n ipv6 trf class val is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TrfClsMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+							 &= atoi(content_buf);
+						IPACMDBG_H("\n ipv6 trf class mask is %d \n", atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV6NextHeaderProtocol_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr
+							 = atoi(content_buf);
+						IPACMDBG_H("\n ipv6 next header protocol is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (atoi(content_buf) != 0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port = 0;
+							IPACMDBG_H("\n tcp source port from %d to %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+							IPACMDBG_H("\n tcp source port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPDestination_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port = 0;
+							IPACMDBG_H("\n tcp dest port from %d to %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+							IPACMDBG_H("\n tcp dest port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ 							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port = 0;
+							IPACMDBG_H("\n udp source port from %d to %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+							IPACMDBG_H("\n udp source port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPDestination_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, UDPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port = 0;
+							IPACMDBG_H("\n UDP dest port from %d to %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+							IPACMDBG_H("\n UDP dest port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, ICMPType_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TYPE;
+						IPACMDBG_H("\n icmp type is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, ICMPCode_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_CODE;
+						IPACMDBG_H("\n icmp code is %d \n",
+								 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, ESPSPI_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SPI;
+						IPACMDBG_H("\n esp spi is %d \n",
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content,str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port = 0;
+							IPACMDBG_H("\n tcp_udp source port from %d to %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+							IPACMDBG_H("\n tcp_udp source port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPDestination_TAG))
+				{
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children, config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name, TCP_UDPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+								= config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port = 0;
+							IPACMDBG_H("\n tcp_udp dest port from %d to %d \n",
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+								config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+							config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+							IPACMDBG_H("\n tcp_udp dest port= %d \n",
+									config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+						}
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+		/* go to sibling */
+		xml_node = xml_node->next;
+	} /* end while */
+	return ret_val;
+}
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
new file mode 100644
index 0000000..9bac7a4
--- /dev/null
+++ b/ipacm/src/IPACM_cfg.xml
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
+	<ODUCFG>
+		<OduMode>router</OduMode>
+		<eMBMS_offload>0</eMBMS_offload>
+	</ODUCFG>
+	<IPACM>
+		<IPACMIface>
+			<Iface>
+			   <Name>rndis0</Name>
+			   <Category>LAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>ecm0</Name>
+			   <Category>LAN</Category>
+			   <Mode>ROUTER</Mode>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data0</Name>
+			   <Category>WAN</Category>
+			   <Mode>ROUTER</Mode>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data1</Name>
+			   <Category>WAN</Category>
+			</Iface>			
+			<Iface>
+			   <Name>rmnet_data2</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data3</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data4</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data5</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data6</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet_data7</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>softap0</Name>
+			   <Category>UNKNOWN</Category>
+			   <WlanMode>full</WlanMode>
+			</Iface>
+			<Iface>
+			   <Name>wlan0</Name>
+			   <Category>UNKNOWN</Category>
+			   <WlanMode>full</WlanMode>
+			</Iface>			
+			<Iface>
+			   <Name>wlan1</Name>
+			   <Category>UNKNOWN</Category>
+			   <WlanMode>full</WlanMode>
+			</Iface>
+			<Iface>
+			   <Name>wlan2</Name>
+			   <Category>UNKNOWN</Category>
+			   <WlanMode>full</WlanMode>
+			</Iface>
+			<Iface>
+			   <Name>wlan3</Name>
+			   <Category>UNKNOWN</Category>
+			   <WlanMode>full</WlanMode>
+			</Iface>
+			<Iface>
+			   <Name>eth0</Name>
+			   <Category>ODU</Category>
+			</Iface>
+			<Iface>
+			   <Name>bridge0</Name>
+			   <Category>VIRTUAL</Category>
+		    </Iface>
+		</IPACMIface>
+		<IPPassthroughFlag>
+			<IPPassthroughMode>0</IPPassthroughMode>
+		</IPPassthroughFlag>
+		<IPACMPrivateSubnet>
+			<Subnet>
+  			   <SubnetAddress>192.168.225.0</SubnetAddress>
+  			   <SubnetMask>255.255.255.0</SubnetMask>
+		    </Subnet>		
+		</IPACMPrivateSubnet>
+		<IPACMALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>21</Port>
+			   <Description>FTP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>554</Port>
+			   <Description>RTSP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>5060</Port>
+			   <Description>SIP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>5060</Port>
+			   <Description>SIP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>1723</Port>
+			   <Description>PPTP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>69</Port>
+			   <Description>TFTP</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>53</Port>
+			   <Description>DNS</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>53</Port>
+			   <Description>DNS</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>10080</Port>
+			   <Description>AMANDA</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>1719</Port>
+			   <Description>H323</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>1720</Port>
+			   <Description>H323</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>6667</Port>
+			   <Description>IRC</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>137</Port>
+			   <Description>NETBIOS_NS</Description>
+		    </ALG>
+			<ALG>
+			   <Protocol>UDP</Protocol>
+			   <Port>138</Port>
+			   <Description>NETBIOS_NS</Description>
+		    </ALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>6566</Port>
+			   <Description>SANE</Description>
+		    </ALG>
+		</IPACMALG>
+		<IPACMNAT>		
+ 	        <MaxNatEntries>500</MaxNatEntries>
+		</IPACMNAT>
+		</IPACM>
+</system>
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
new file mode 100644
index 0000000..7a62a75
--- /dev/null
+++ b/ipacm/src/Makefile.am
@@ -0,0 +1,55 @@
+AM_CPPFLAGS = -I./../inc \
+	      -I$(top_srcdir)/ipanat/inc \
+	      ${LIBXML_CFLAGS}
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+AM_CPPFLAGS	+= -DDEBUG -g -DFEATURE_ETH_BRIDGE_LE
+AM_CPPFLAGS += -DFEATURE_IPA_V3
+
+ipacm_SOURCES =	IPACM_Main.cpp \
+		IPACM_Conntrack_NATApp.cpp\
+		IPACM_ConntrackClient.cpp \
+		IPACM_ConntrackListener.cpp \
+		IPACM_EvtDispatcher.cpp \
+		IPACM_Config.cpp \
+		IPACM_CmdQueue.cpp \
+		IPACM_Log.cpp \
+		IPACM_Filtering.cpp \
+		IPACM_Routing.cpp \
+		IPACM_Header.cpp \
+		IPACM_Lan.cpp \
+		IPACM_Iface.cpp \
+		IPACM_Wlan.cpp \
+		IPACM_Wan.cpp \
+		IPACM_IfaceManager.cpp \
+		IPACM_Neighbor.cpp \
+		IPACM_Netlink.cpp \
+		IPACM_Xml.cpp \
+		IPACM_LanToLan.cpp
+
+bin_PROGRAMS  =  ipacm
+
+requiredlibs =  ${LIBXML_LIB} -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
+               ../../ipanat/src/libipanat.la
+
+AM_CPPFLAGS += "-std=c++0x"
+
+if USE_GLIB
+ipacm_CFLAGS  = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
+ipacm_LDFLAGS = -lpthread @GLIB_LIBS@
+ipacm_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+ipacm_CFLAGS = $(AM_CFLAGS)
+ipacm_LDFLAGS = -lpthread
+ipacm_CPPFLAGS = $(AM_CPPFLAGS)
+endif
+ipacm_LDADD =  $(requiredlibs)
+
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+etcdir = ${sysconfdir}
+etc_SCRIPTS = IPACM_cfg.xml
+
+init_ddir = ${sysconfdir}/init.d
+init_d_SCRIPTS = start_ipacm_le
diff --git a/ipacm/src/mobileap_firewall.xml b/ipacm/src/mobileap_firewall.xml
new file mode 100644
index 0000000..84da527
--- /dev/null
+++ b/ipacm/src/mobileap_firewall.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
+	<MobileAPFirewallCfg>					
+	<FirewallEnabled>1</FirewallEnabled> 
+      <FirewallPktsAllowed>0</FirewallPktsAllowed> 
+	</MobileAPFirewallCfg>
+</system>
diff --git a/ipacm/src/start_ipacm_le b/ipacm/src/start_ipacm_le
new file mode 100644
index 0000000..3541a0b
--- /dev/null
+++ b/ipacm/src/start_ipacm_le
@@ -0,0 +1,57 @@
+#! /bin/sh
+#
+################################ 
+# 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.
+################################
+
+# ipacm   init.d script to start the data-ipa Software's ipacm daemon
+
+set -e
+
+case "$1" in
+  start)
+        echo -n "Starting ipacm: "
+        start-stop-daemon -S -b -a ipacm
+        echo "done"
+        ;;
+  stop)
+        echo -n "Stopping ipacm: "
+        start-stop-daemon -K -n ipacm
+        echo "done"
+        ;;
+  restart)
+        $0 stop
+        $0 start
+        ;;
+  *)
+        echo "Usage ipacm { start | stop | restart}" >&2
+        exit 1
+        ;;
+esac
+
+exit 0
diff --git a/ipanat/inc/ipa_nat_drv.h b/ipanat/inc/ipa_nat_drv.h
new file mode 100644
index 0000000..04e3af9
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drv.h
@@ -0,0 +1,116 @@
+/*
+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..6f9b1bd
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drvi.h
@@ -0,0 +1,482 @@
+/*
+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 <errno.h>
+#include <pthread.h>
+
+#include "ipa_nat_logi.h"
+
+#define NAT_DUMP
+
+/*======= 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
+
+	uint16_t cur_tbl_cnt;
+	uint16_t cur_expn_tbl_cnt;
+};
+
+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*,
+				nat_table_type tbl_type,
+				uint16_t indx_tbl_entry);
+uint32_t ipa_nati_get_entry_offset(
+				struct ipa_nat_ip4_table_cache*,
+				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*, uint16_t*);
+
+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);
+
+int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+				const ipa_nat_ipv4_rule *clnt_rule,
+				uint32_t *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);
+
+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);
+
+uint16_t Read16BitFieldValue(uint32_t param,
+				ipa_nat_rule_field_type fld_type);
+
+/* ========================================================
+								Debug functions
+   ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nati_print_rule(struct ipa_nat_rule*, uint32_t);
+void ipa_nat_dump_ipv4_table(uint32_t);
+void ipa_nati_print_index_rule(struct ipa_nat_indx_tbl_rule*,
+				uint32_t, uint16_t);
+int ipa_nati_query_nat_rules(uint32_t, nat_table_type);
+#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..5f79cc6
--- /dev/null
+++ b/ipanat/inc/ipa_nat_logi.h
@@ -0,0 +1,73 @@
+/* 
+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>
+#include <syslog.h>
+
+#define PERROR(fmt) printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+                    perror(fmt);
+
+#define IPAERR(fmt, ...)  printf("ERR: %s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+
+#ifdef DEBUG
+#define IPADBG(fmt, ...) printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+
+#define IPADUMP(fmt, ...) printf(fmt, ##__VA_ARGS__);
+
+#else
+#define IPADBG(fmt, ...)
+#define IPADUMP(fmt, ...)
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPA_NAT_LOGI_H */
diff --git a/ipanat/src/Android.mk b/ipanat/src/Android.mk
new file mode 100644
index 0000000..a54a57a
--- /dev/null
+++ b/ipanat/src/Android.mk
@@ -0,0 +1,28 @@
+BOARD_PLATFORM_LIST := msm8916
+BOARD_PLATFORM_LIST += msm8909
+ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
+ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH)))
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../inc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_SRC_FILES := ipa_nat_drv.c \
+                   ipa_nat_drvi.c
+
+LOCAL_CFLAGS := -DDEBUG
+LOCAL_MODULE := libipanat
+LOCAL_MODULE_TAGS := optional
+LOCAL_PRELINK_MODULE := false
+LOCAL_CLANG := true
+include $(BUILD_SHARED_LIBRARY)
+
+endif # $(TARGET_ARCH)
+endif
+endif
\ No newline at end of file
diff --git a/ipanat/src/Makefile.am b/ipanat/src/Makefile.am
new file mode 100644
index 0000000..8bdb9b8
--- /dev/null
+++ b/ipanat/src/Makefile.am
@@ -0,0 +1,21 @@
+AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+AM_CFLAGS += -I./../inc
+#AM_CFLAGS += -DDEBUG -g
+
+common_CFLAGS =  -DUSE_GLIB @GLIB_CFLAGS@
+common_LDFLAGS = -lrt @GLIB_LIBS@
+
+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) $(common_CFLAGS)
+libipanat_la_LDFLAGS = -shared $(common_LDFLAGS) -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..66504e1
--- /dev/null
+++ b/ipanat/src/ipa_nat_drv.c
@@ -0,0 +1,175 @@
+/*
+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 -EINVAL;
+  }
+
+  ret = ipa_nati_add_ipv4_tbl(public_ip_addr,
+								number_of_entries,
+								tbl_hdl);
+  if (ret != 0) {
+    IPAERR("unable to add table \n");
+    return -EINVAL;
+  }
+  IPADBG("Returning table handle 0x%x\n", *tbl_hdl);
+
+  return ret;
+} /* __ipa_nat_add_ipv4_tbl() */
+
+/**
+ * ipa_nat_del_ipv4_tbl() - delete ipv4 table
+ * @table_handle: [in] Handle of ipv4 nat table
+ *
+ * To delete given ipv4 nat table
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_tbl(uint32_t tbl_hdl)
+{
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+      tbl_hdl > IPA_NAT_MAX_IP4_TBLS) {
+    IPAERR("invalid table handle passed \n");
+    return -EINVAL;
+  }
+  IPADBG("Passed Table Handle: 0x%x\n", tbl_hdl);
+
+  return ipa_nati_del_ipv4_table(tbl_hdl);
+}
+
+/**
+ * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule: [in]  Pointer to new rule
+ * @rule_handle: [out] Return the handle to rule
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_rule(uint32_t tbl_hdl,
+		const ipa_nat_ipv4_rule *clnt_rule,
+		uint32_t *rule_hdl)
+{
+  int result = -EINVAL;
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+      tbl_hdl > IPA_NAT_MAX_IP4_TBLS || NULL == rule_hdl ||
+      NULL == clnt_rule) {
+    IPAERR("invalide table handle passed \n");
+    return result;
+  }
+  IPADBG("Passed Table handle: 0x%x\n", tbl_hdl);
+
+  if (ipa_nati_add_ipv4_rule(tbl_hdl, clnt_rule, rule_hdl) != 0) {
+		return result;
+	}
+
+  IPADBG("returning rule handle 0x%x\n", *rule_hdl);
+  return 0;
+}
+
+
+/**
+ * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_rule(uint32_t tbl_hdl,
+		uint32_t rule_hdl)
+{
+  int result = -EINVAL;
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+      IPA_NAT_INVALID_NAT_ENTRY == rule_hdl) {
+    IPAERR("invalide parameters\n");
+    return result;
+  }
+  IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+  result = ipa_nati_del_ipv4_rule(tbl_hdl, rule_hdl);
+  if (result) {
+    IPAERR("unable to delete rule from hw \n");
+    return result;
+  }
+
+  return 0;
+}
+
+/**
+ * ipa_nat_query_timestamp() - to query timestamp
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ * @time_stamp: [out] time stamp of rule
+ *
+ * To retrieve the timestamp that lastly the
+ * nat rule was accessed
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_query_timestamp(uint32_t  tbl_hdl,
+		uint32_t  rule_hdl,
+		uint32_t  *time_stamp)
+{
+
+  if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS ||
+      NULL == time_stamp) {
+    IPAERR("invalid parameters passed \n");
+    return -EINVAL;
+  }
+  IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+  return ipa_nati_query_timestamp(tbl_hdl, rule_hdl, time_stamp);
+}
+
+
diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c
new file mode 100644
index 0000000..faa8c8c
--- /dev/null
+++ b/ipanat/src/ipa_nat_drvi.c
@@ -0,0 +1,2340 @@
+/*
+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"
+
+#ifdef USE_GLIB
+#include <glib.h>
+#define strlcpy g_strlcpy
+#endif
+
+struct ipa_nat_cache ipv4_nat_cache;
+pthread_mutex_t nat_mutex    = PTHREAD_MUTEX_INITIALIZER;
+
+/* ------------------------------------------
+		UTILITY FUNCTIONS START
+	 --------------------------------------------*/
+
+/**
+ * UpdateSwSpecParams() - updates sw specific params
+ * @rule: [in/out] nat table rule
+ * @param_type: [in] which param need to update
+ * @value: [in] value of param
+ *
+ * Update SW specific params in the passed rule.
+ *
+ * Returns: None
+ */
+void UpdateSwSpecParams(struct ipa_nat_rule *rule,
+															uint8_t param_type,
+															uint32_t value)
+{
+	uint32_t temp = rule->sw_spec_params;
+
+	if (IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE == param_type) {
+		value = (value << INDX_TBL_ENTRY_SIZE_IN_BITS);
+		temp &= 0x0000FFFF;
+	} else {
+		temp &= 0xFFFF0000;
+	}
+
+	temp = (temp | value);
+	rule->sw_spec_params = temp;
+	return;
+}
+
+/**
+ * Read8BitFieldValue()
+ * @rule: [in/out]
+ * @param_type: [in]
+ * @value: [in]
+ *
+ *
+ *
+ * Returns: None
+ */
+
+uint8_t Read8BitFieldValue(uint32_t param,
+														ipa_nat_rule_field_type fld_type)
+{
+	void *temp = (void *)&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)
+{
+	int ret;
+
+	ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_ALLOC_NAT_MEM, mem);
+	if (ret != 0) {
+		perror("CreateNatDevice(): ioctl error value");
+		IPAERR("unable to post nat mem init. Error ;%d\n", ret);
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		return -EINVAL;
+	}
+	IPADBG("posted IPA_IOC_ALLOC_NAT_MEM to kernel successfully\n");
+	return 0;
+}
+
+/**
+ * GetNearest2Power() - Returns the nearest power of 2
+ * @num: [in] given number
+ * @ret: [out] nearest power of 2
+ *
+ * Returns the nearest power of 2 for a
+ * given number
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int GetNearest2Power(uint16_t num, uint16_t *ret)
+{
+	uint16_t number = num;
+	uint16_t tmp = 1;
+	*ret = 0;
+
+	if (0 == num) {
+		return -EINVAL;
+	}
+
+	if (1 == num) {
+		*ret = 2;
+		return 0;
+	}
+
+	for (;;) {
+		if (1 == num) {
+			if (number != tmp) {
+				tmp *= 2;
+			}
+
+			*ret = tmp;
+			return 0;
+		}
+
+		num >>= 1;
+		tmp *= 2;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * GetNearestEven() - Returns the nearest even number
+ * @num: [in] given number
+ * @ret: [out] nearest even number
+ *
+ * Returns the nearest even number for a given number
+ *
+ * Returns: 0 on success, negative on failure
+ */
+void GetNearestEven(uint16_t num, uint16_t *ret)
+{
+
+	if (num < 2) {
+		*ret = 2;
+		return;
+	}
+
+	while ((num % 2) != 0) {
+		num = num + 1;
+	}
+
+	*ret = num;
+	return;
+}
+
+/**
+ * dst_hash() - Find the index into ipv4 base table
+ * @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) {
+		/* Increase the current expansion table count */
+		tbl_ptr->cur_expn_tbl_cnt++;
+
+		/* Update the index into table */
+		rule_hdl = tbl_entry - tbl_ptr->table_entries;
+		rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+		/* Update the table type mask */
+		rule_hdl = (rule_hdl | IPA_NAT_RULE_HDL_TBL_TYPE_MASK);
+	} else {
+		/* Increase the current count */
+		tbl_ptr->cur_tbl_cnt++;
+
+		rule_hdl = tbl_entry;
+		rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+	}
+
+	for (; cnt < (tbl_ptr->table_entries + tbl_ptr->expn_table_entries); cnt++) {
+		if (IPA_NAT_INVALID_NAT_ENTRY == tbl_ptr->rule_id_array[cnt]) {
+			tbl_ptr->rule_id_array[cnt] = rule_hdl;
+			return cnt + 1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle
+ * @tbl_hdl:	[in] nat table rule
+ * @rule_hdl: [in] nat rule handle
+ * @expn_tbl: [out] expansion table or not
+ * @tbl_entry: [out] index into table
+ *
+ * Parse the rule handle to retrieve the nat table
+ * type and entry of nat table
+ *
+ * Returns: None
+ */
+void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_index,
+				uint16_t rule_hdl, uint8_t *expn_tbl,
+				uint16_t *tbl_entry)
+{
+	struct ipa_nat_ip4_table_cache *tbl_ptr;
+	uint16_t rule_id;
+
+	*expn_tbl = 0;
+	*tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_index];
+
+	if (rule_hdl >= (tbl_ptr->table_entries + tbl_ptr->expn_table_entries)) {
+		IPAERR("invalid rule handle\n");
+		return;
+	}
+
+	rule_id = tbl_ptr->rule_id_array[rule_hdl-1];
+
+	/* Retrieve the table type */
+	*expn_tbl = 0;
+	if (rule_id & IPA_NAT_RULE_HDL_TBL_TYPE_MASK) {
+		*expn_tbl = 1;
+	}
+
+	/* Retrieve the table entry */
+	*tbl_entry = (rule_id >> IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+	return;
+}
+
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+						nat_table_type tbl_type,
+						uint16_t	tbl_entry)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	uint32_t ret = 0;
+
+	if (IPA_NAT_EXPN_TBL == tbl_type) {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+	} else {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+	}
+
+	ret = (char *)&tbl_ptr[tbl_entry] - (char *)tbl_ptr;
+	ret += cache_ptr->tbl_addr_offset;
+	return ret;
+}
+
+uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+								nat_table_type tbl_type,
+								uint16_t indx_tbl_entry)
+{
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	uint32_t ret = 0;
+
+	if (IPA_NAT_INDEX_EXPN_TBL == tbl_type) {
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+	} else {
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+	}
+
+	ret = (char *)&indx_tbl_ptr[indx_tbl_entry] - (char *)indx_tbl_ptr;
+	ret += cache_ptr->tbl_addr_offset;
+	return ret;
+}
+
+/* ------------------------------------------
+		UTILITY FUNCTIONS END
+--------------------------------------------*/
+
+/* ------------------------------------------
+	 Main Functions
+--------------------------------------------**/
+void ipa_nati_reset_tbl(uint8_t tbl_indx)
+{
+	uint16_t table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+	uint16_t expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].expn_table_entries;
+
+	/* Base table */
+	IPADBG("memset() base table to 0, %p\n",
+				 ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr);
+
+	memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr,
+				 0,
+				 IPA_NAT_TABLE_ENTRY_SIZE * table_entries);
+
+	/* Base expansino table */
+	IPADBG("memset() expn base table to 0, %p\n",
+				 ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr);
+
+	memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr,
+				 0,
+				 IPA_NAT_TABLE_ENTRY_SIZE * expn_table_entries);
+
+	/* Index table */
+	IPADBG("memset() index table to 0, %p\n",
+				 ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr);
+
+	memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr,
+				 0,
+				 IPA_NAT_INDEX_TABLE_ENTRY_SIZE * table_entries);
+
+	/* Index expansion table */
+	IPADBG("memset() index expn table to 0, %p\n",
+				 ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr);
+
+	memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr,
+				 0,
+				 IPA_NAT_INDEX_TABLE_ENTRY_SIZE * expn_table_entries);
+
+	IPADBG("returning from ipa_nati_reset_tbl()\n");
+	return;
+}
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+				uint16_t number_of_entries,
+				uint32_t *tbl_hdl)
+{
+	struct ipa_ioc_nat_alloc_mem mem;
+	uint8_t tbl_indx = ipv4_nat_cache.table_cnt;
+	uint16_t table_entries, expn_table_entries;
+	int ret;
+
+	*tbl_hdl = 0;
+	/* Allocate table */
+	memset(&mem, 0, sizeof(mem));
+	ret = ipa_nati_alloc_table(number_of_entries,
+														 &mem,
+														 &table_entries,
+														 &expn_table_entries);
+	if (0 != ret) {
+		IPAERR("unable to allocate nat table\n");
+		return -ENOMEM;
+	}
+
+	/* Update the cache
+		 The (IPA_NAT_UNUSED_BASE_ENTRIES/2) indicates zero entry entries
+		 for both base and expansion table
+	*/
+	ret = ipa_nati_update_cache(&mem,
+															public_ip_addr,
+															table_entries,
+															expn_table_entries);
+	if (0 != ret) {
+		IPAERR("unable to update cache Error: %d\n", ret);
+		return -EINVAL;
+	}
+
+	/* Reset the nat table before posting init cmd */
+	ipa_nati_reset_tbl(tbl_indx);
+
+	/* Initialize the ipa hw with nat table dimensions */
+	ret = ipa_nati_post_ipv4_init_cmd(tbl_indx);
+	if (0 != ret) {
+		IPAERR("unable to post nat_init command Error %d\n", ret);
+		return -EINVAL;
+	}
+
+	/* Return table handle */
+	ipv4_nat_cache.table_cnt++;
+	*tbl_hdl = ipv4_nat_cache.table_cnt;
+
+#ifdef NAT_DUMP
+	ipa_nat_dump_ipv4_table(*tbl_hdl);
+#endif
+	return 0;
+}
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+				struct ipa_ioc_nat_alloc_mem *mem,
+				uint16_t *table_entries,
+				uint16_t *expn_table_entries)
+{
+	int fd = 0, ret;
+	uint16_t total_entries;
+
+	/* Copy the table name */
+	strlcpy(mem->dev_name, NAT_DEV_NAME, IPA_RESOURCE_NAME_MAX);
+
+	/* Calculate the size for base table and expansion table */
+	*table_entries = (uint16_t)(number_of_entries * IPA_NAT_BASE_TABLE_PERCENTAGE);
+	if (*table_entries == 0) {
+		*table_entries = 1;
+	}
+	if (GetNearest2Power(*table_entries, table_entries)) {
+		IPAERR("unable to calculate power of 2\n");
+		return -EINVAL;
+	}
+
+	*expn_table_entries = (uint16_t)(number_of_entries * IPA_NAT_EXPANSION_TABLE_PERCENTAGE);
+	GetNearestEven(*expn_table_entries, expn_table_entries);
+
+	total_entries = (*table_entries)+(*expn_table_entries);
+
+	/* Calclate the memory size for both table and index table entries */
+	mem->size = (IPA_NAT_TABLE_ENTRY_SIZE * total_entries);
+	IPADBG("Nat Table size: %d\n", mem->size);
+	mem->size += (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * total_entries);
+	IPADBG("Nat Base and Index Table size: %d\n", mem->size);
+
+	if (!ipv4_nat_cache.ipa_fd) {
+		fd = open(IPA_DEV_NAME, O_RDONLY);
+		if (fd < 0) {
+			perror("ipa_nati_alloc_table(): open error value:");
+			IPAERR("unable to open ipa device\n");
+			return -EIO;
+		}
+		ipv4_nat_cache.ipa_fd = fd;
+	}
+
+	ret = CreateNatDevice(mem);
+	return ret;
+}
+
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *mem,
+				uint32_t public_addr,
+				uint16_t tbl_entries,
+				uint16_t expn_tbl_entries)
+{
+	uint32_t index = ipv4_nat_cache.table_cnt;
+	char *ipv4_rules_addr = NULL;
+
+	int fd = 0;
+	int flags = MAP_SHARED;
+	int prot = PROT_READ | PROT_WRITE;
+	off_t offset = 0;
+#ifdef IPA_ON_R3PC
+	int ret = 0;
+	uint32_t nat_mem_offset = 0;
+#endif
+
+	ipv4_nat_cache.ip4_tbl[index].valid = IPA_NAT_TABLE_VALID;
+	ipv4_nat_cache.ip4_tbl[index].public_addr = public_addr;
+	ipv4_nat_cache.ip4_tbl[index].size = mem->size;
+	ipv4_nat_cache.ip4_tbl[index].tbl_addr_offset = mem->offset;
+
+	ipv4_nat_cache.ip4_tbl[index].table_entries = tbl_entries;
+	ipv4_nat_cache.ip4_tbl[index].expn_table_entries = expn_tbl_entries;
+
+	IPADBG("num of ipv4 rules:%d\n", tbl_entries);
+	IPADBG("num of ipv4 expn rules:%d\n", expn_tbl_entries);
+
+	/* allocate memory for nat index expansion table */
+	if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta) {
+		ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta =
+			 malloc(sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+
+		if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta) {
+			IPAERR("Fail to allocate ipv4 index expansion table meta\n");
+			return 0;
+		}
+
+		memset(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta,
+					 0,
+					 sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+	}
+
+	/* Allocate memory for rule_id_array */
+	if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array) {
+		ipv4_nat_cache.ip4_tbl[index].rule_id_array =
+			 malloc(sizeof(uint16_t) * (tbl_entries + expn_tbl_entries));
+
+		if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array) {
+			IPAERR("Fail to allocate rule id array\n");
+			return 0;
+		}
+
+		memset(ipv4_nat_cache.ip4_tbl[index].rule_id_array,
+					 0,
+					 sizeof(uint16_t) * (tbl_entries + expn_tbl_entries));
+	}
+
+
+	/* open the nat table */
+	strlcpy(mem->dev_name, NAT_DEV_FULL_NAME, IPA_RESOURCE_NAME_MAX);
+	fd = open(mem->dev_name, O_RDWR);
+	if (fd < 0) {
+		perror("ipa_nati_update_cache(): open error value:");
+		IPAERR("unable to open nat device. Error:%d\n", fd);
+		return -EIO;
+	}
+
+	/* copy the nat table name */
+	strlcpy(ipv4_nat_cache.ip4_tbl[index].table_name,
+					mem->dev_name,
+					IPA_RESOURCE_NAME_MAX);
+	ipv4_nat_cache.ip4_tbl[index].nat_fd = fd;
+
+	/* open the nat device Table */
+#ifndef IPA_ON_R3PC
+	ipv4_rules_addr = (void *)mmap(NULL, mem->size,
+																 prot, flags,
+																 fd, offset);
+#else
+	IPADBG("user space r3pc\n");
+	ipv4_rules_addr = (void *)mmap((caddr_t)0, NAT_MMAP_MEM_SIZE,
+																 prot, flags,
+																 fd, offset);
+#endif
+	if (MAP_FAILED  == ipv4_rules_addr) {
+		perror("unable to mmap the memory\n");
+		return -EINVAL;
+	}
+
+#ifdef IPA_ON_R3PC
+	ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_NAT_OFFSET, &nat_mem_offset);
+	if (ret != 0) {
+		perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+		IPAERR("unable to post ant offset cmd Error: %d\n", ret);
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		return -EIO;
+	}
+	ipv4_rules_addr += nat_mem_offset;
+	ipv4_nat_cache.ip4_tbl[index].mmap_offset = nat_mem_offset;
+#endif
+
+	IPADBG("mmap return value 0x%lx\n", (long unsigned int)ipv4_rules_addr);
+
+	ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr = ipv4_rules_addr;
+
+	ipv4_nat_cache.ip4_tbl[index].ipv4_expn_rules_addr =
+	ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * tbl_entries);
+
+	ipv4_nat_cache.ip4_tbl[index].index_table_addr =
+	ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries));
+
+	ipv4_nat_cache.ip4_tbl[index].index_table_expn_addr =
+	ipv4_rules_addr +
+	(IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries))+
+	(IPA_NAT_INDEX_TABLE_ENTRY_SIZE * tbl_entries);
+
+	return 0;
+}
+
+/* comment: check the implementation once
+	 offset should be in terms of byes */
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index)
+{
+	struct ipa_ioc_v4_nat_init cmd;
+	uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_index].tbl_addr_offset;
+	int ret;
+
+	cmd.tbl_index = tbl_index;
+
+	cmd.ipv4_rules_offset = offset;
+	cmd.expn_rules_offset = cmd.ipv4_rules_offset +
+	(ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+	cmd.index_offset = cmd.expn_rules_offset +
+	(ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+	cmd.index_expn_offset = cmd.index_offset +
+	(ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_INDEX_TABLE_ENTRY_SIZE);
+
+	cmd.table_entries  = ipv4_nat_cache.ip4_tbl[tbl_index].table_entries - 1;
+	cmd.expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries;
+
+	cmd.ip_addr = ipv4_nat_cache.ip4_tbl[tbl_index].public_addr;
+
+	ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_INIT_NAT, &cmd);
+	if (ret != 0) {
+		perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+		IPAERR("unable to post init cmd Error: %d\n", ret);
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		return -EINVAL;
+	}
+	IPADBG("Posted IPA_IOC_V4_INIT_NAT to kernel successfully\n");
+
+	return 0;
+}
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl)
+{
+	uint8_t index = (uint8_t)(tbl_hdl - 1);
+	void *addr = (void *)ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr;
+	struct ipa_ioc_v4_nat_del del_cmd;
+	int ret;
+
+	if (!ipv4_nat_cache.ip4_tbl[index].valid) {
+		IPAERR("invalid table handle passed\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (pthread_mutex_lock(&nat_mutex) != 0) {
+		ret = -1;
+		goto lock_mutex_fail;
+	}
+
+	/* unmap the device memory from user space */
+#ifndef IPA_ON_R3PC
+	munmap(addr, ipv4_nat_cache.ip4_tbl[index].size);
+#else
+	addr = (char *)addr - ipv4_nat_cache.ip4_tbl[index].mmap_offset;
+	munmap(addr, NAT_MMAP_MEM_SIZE);
+#endif
+
+	/* close the file descriptor of nat device */
+	if (close(ipv4_nat_cache.ip4_tbl[index].nat_fd)) {
+		IPAERR("unable to close the file descriptor\n");
+		ret = -EINVAL;
+		if (pthread_mutex_unlock(&nat_mutex) != 0)
+			goto unlock_mutex_fail;
+		goto fail;
+	}
+
+	del_cmd.table_index = index;
+	del_cmd.public_ip_addr = ipv4_nat_cache.ip4_tbl[index].public_addr;
+	ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_DEL_NAT, &del_cmd);
+	if (ret != 0) {
+		perror("ipa_nati_del_ipv4_table(): ioctl error value");
+		IPAERR("unable to post nat del command init Error: %d\n", ret);
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		ret = -EINVAL;
+		if (pthread_mutex_unlock(&nat_mutex) != 0)
+			goto unlock_mutex_fail;
+		goto fail;
+	}
+	IPAERR("posted IPA_IOC_V4_DEL_NAT to kernel successfully\n");
+
+	free(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta);
+	free(ipv4_nat_cache.ip4_tbl[index].rule_id_array);
+
+	memset(&ipv4_nat_cache.ip4_tbl[index],
+				 0,
+				 sizeof(ipv4_nat_cache.ip4_tbl[index]));
+
+	/* Decrease the table count by 1*/
+	ipv4_nat_cache.table_cnt--;
+
+	if (pthread_mutex_unlock(&nat_mutex) != 0) {
+		ret = -1;
+		goto unlock_mutex_fail;
+	}
+
+	return 0;
+
+lock_mutex_fail:
+	IPAERR("unable to lock the nat mutex\n");
+	return ret;
+
+unlock_mutex_fail:
+	IPAERR("unable to unlock the nat mutex\n");
+
+fail:
+	return ret;
+}
+
+int ipa_nati_query_timestamp(uint32_t  tbl_hdl,
+				uint32_t  rule_hdl,
+				uint32_t  *time_stamp)
+{
+	uint8_t tbl_index = (uint8_t)(tbl_hdl - 1);
+	uint8_t expn_tbl = 0;
+	uint16_t tbl_entry = 0;
+	struct ipa_nat_rule *tbl_ptr = NULL;
+
+	if (!ipv4_nat_cache.ip4_tbl[tbl_index].valid) {
+		IPAERR("invalid table handle\n");
+		return -EINVAL;
+	}
+
+	if (pthread_mutex_lock(&nat_mutex) != 0) {
+		IPAERR("unable to lock the nat mutex\n");
+		return -1;
+	}
+
+	ipa_nati_parse_ipv4_rule_hdl(tbl_index, (uint16_t)rule_hdl,
+															 &expn_tbl, &tbl_entry);
+
+	tbl_ptr =
+	(struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_rules_addr;
+	if (expn_tbl) {
+		tbl_ptr =
+			 (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_expn_rules_addr;
+	}
+
+	if (tbl_ptr)
+		*time_stamp = Read32BitFieldValue(tbl_ptr[tbl_entry].ts_proto,
+					TIME_STAMP_FIELD);
+
+	if (pthread_mutex_unlock(&nat_mutex) != 0) {
+		IPAERR("unable to unlock the nat mutex\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+				const ipa_nat_ipv4_rule *clnt_rule,
+				uint32_t *rule_hdl)
+{
+	struct ipa_nat_ip4_table_cache *tbl_ptr;
+	struct ipa_nat_sw_rule sw_rule;
+	struct ipa_nat_indx_tbl_sw_rule index_sw_rule;
+	uint16_t new_entry, new_index_tbl_entry;
+
+	memset(&sw_rule, 0, sizeof(sw_rule));
+	memset(&index_sw_rule, 0, sizeof(index_sw_rule));
+
+	/* Generate rule from client input */
+	if (ipa_nati_generate_rule(tbl_hdl, clnt_rule,
+					&sw_rule, &index_sw_rule,
+					&new_entry, &new_index_tbl_entry)) {
+		IPAERR("unable to generate rule\n");
+		return -EINVAL;
+	}
+
+	tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+	ipa_nati_copy_ipv4_rule_to_hw(tbl_ptr, &sw_rule, new_entry, (uint8_t)(tbl_hdl-1));
+	ipa_nati_copy_ipv4_index_rule_to_hw(tbl_ptr,
+																			&index_sw_rule,
+																			new_index_tbl_entry,
+																			(uint8_t)(tbl_hdl-1));
+
+	IPADBG("new entry:%d, new index entry: %d\n", new_entry, new_index_tbl_entry);
+	if (ipa_nati_post_ipv4_dma_cmd((uint8_t)(tbl_hdl - 1), new_entry)) {
+		IPAERR("unable to post dma command\n");
+		return -EIO;
+	}
+
+	/* Generate rule handle */
+	*rule_hdl  = ipa_nati_make_rule_hdl((uint16_t)tbl_hdl, new_entry);
+	if (!(*rule_hdl)) {
+		IPAERR("unable to generate rule handle\n");
+		return -EINVAL;
+	}
+
+#ifdef NAT_DUMP
+	ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+	return 0;
+}
+
+int ipa_nati_generate_rule(uint32_t tbl_hdl,
+				const ipa_nat_ipv4_rule *clnt_rule,
+				struct ipa_nat_sw_rule *rule,
+				struct ipa_nat_indx_tbl_sw_rule *index_sw_rule,
+				uint16_t *tbl_entry,
+				uint16_t *indx_tbl_entry)
+{
+	struct ipa_nat_ip4_table_cache *tbl_ptr;
+	uint16_t tmp;
+
+	if (NULL == clnt_rule || NULL == index_sw_rule ||
+			NULL == rule || NULL == tbl_entry  ||
+			NULL == indx_tbl_entry) {
+		IPAERR("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+
+	*tbl_entry = ipa_nati_generate_tbl_rule(clnt_rule,
+																					rule,
+																					tbl_ptr);
+	if (IPA_NAT_INVALID_NAT_ENTRY == *tbl_entry) {
+		IPAERR("unable to generate table entry\n");
+		return -EINVAL;
+	}
+
+	index_sw_rule->tbl_entry = *tbl_entry;
+	*indx_tbl_entry = ipa_nati_generate_index_rule(clnt_rule,
+																								 index_sw_rule,
+																								 tbl_ptr);
+	if (IPA_NAT_INVALID_NAT_ENTRY == *indx_tbl_entry) {
+		IPAERR("unable to generate index table entry\n");
+		return -EINVAL;
+	}
+
+	rule->indx_tbl_entry = *indx_tbl_entry;
+	if (*indx_tbl_entry >= tbl_ptr->table_entries) {
+		tmp = *indx_tbl_entry - tbl_ptr->table_entries;
+		tbl_ptr->index_expn_table_meta[tmp].prev_index = index_sw_rule->prev_index;
+	}
+
+	return 0;
+}
+
+uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule,
+						struct ipa_nat_sw_rule *sw_rule,
+						struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+	uint32_t pub_ip_addr;
+	uint16_t prev = 0, nxt_indx = 0, new_entry;
+	struct ipa_nat_rule *tbl = NULL, *expn_tbl = NULL;
+
+	pub_ip_addr = 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;
+	} else { /* check for more than one collision	*/
+		/* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+		nxt_indx = Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port,
+																	 NEXT_INDEX_FIELD);
+
+		while (nxt_indx != IPA_NAT_INVALID_NAT_ENTRY) {
+			prev = nxt_indx;
+
+			nxt_indx -= tbl_ptr->table_entries;
+			nxt_indx = Read16BitFieldValue(expn_tbl[nxt_indx].nxt_indx_pub_port,
+																		 NEXT_INDEX_FIELD);
+
+			/* Handling error case */
+			if (prev == nxt_indx) {
+				IPAERR("Error: Prev index:%d and next:%d index should not be same\n", prev, nxt_indx);
+				return IPA_NAT_INVALID_NAT_ENTRY;
+			}
+		}
+
+		sw_rule->prev_index = prev;
+	}
+
+	/* On collision check for the free entry in expansion table */
+	new_entry = ipa_nati_expn_tbl_free_entry(expn_tbl,
+					tbl_ptr->expn_table_entries);
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == new_entry) {
+		/* Expansion table is full return*/
+		IPAERR("Expansion table is full\n");
+		IPAERR("Current Table: %d & Expn Entries: %d\n",
+			   tbl_ptr->cur_tbl_cnt, tbl_ptr->cur_expn_tbl_cnt);
+		return IPA_NAT_INVALID_NAT_ENTRY;
+	}
+	new_entry += tbl_ptr->table_entries;
+
+	IPADBG("new entry index %d\n", new_entry);
+	return new_entry;
+}
+
+/* returns expn table entry index */
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+						uint16_t size)
+{
+	int cnt;
+
+	for (cnt = 1; cnt < size; cnt++) {
+		if (!Read16BitFieldValue(expn_tbl[cnt].ip_cksm_enbl,
+														 ENABLE_FIELD)) {
+			IPADBG("new expansion table entry index %d\n", cnt);
+			return cnt;
+		}
+	}
+
+	IPAERR("nat expansion table is full\n");
+	return 0;
+}
+
+uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule,
+						struct ipa_nat_indx_tbl_sw_rule *sw_rule,
+						struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+	struct ipa_nat_indx_tbl_rule *indx_tbl, *indx_expn_tbl;
+	uint16_t prev = 0, nxt_indx = 0, new_entry;
+
+	indx_tbl =
+	(struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_addr;
+	indx_expn_tbl =
+	(struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_expn_addr;
+
+	new_entry = src_hash(clnt_rule->private_ip,
+											 clnt_rule->private_port,
+											 clnt_rule->target_ip,
+											 clnt_rule->target_port,
+											 clnt_rule->protocol,
+											 tbl_ptr->table_entries-1);
+
+	/* check whether there is any collision
+		 if no collision return */
+	if (!Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+													 INDX_TBL_TBL_ENTRY_FIELD)) {
+		sw_rule->prev_index = 0;
+		IPADBG("Source Nat Index Table Entry %d\n", new_entry);
+		return new_entry;
+	}
+
+	/* check for more than one collision	*/
+	if (Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+													INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) {
+		sw_rule->prev_index = new_entry;
+		IPADBG("First collosion. Entry %d\n", new_entry);
+	} else {
+		/* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+		nxt_indx = Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+																	 INDX_TBL_NEXT_INDEX_FILED);
+
+		while (nxt_indx != IPA_NAT_INVALID_NAT_ENTRY) {
+			prev = nxt_indx;
+
+			nxt_indx -= tbl_ptr->table_entries;
+			nxt_indx = Read16BitFieldValue(indx_expn_tbl[nxt_indx].tbl_entry_nxt_indx,
+																		 INDX_TBL_NEXT_INDEX_FILED);
+
+			/* Handling error case */
+			if (prev == nxt_indx) {
+				IPAERR("Error: Prev:%d and next:%d index should not be same\n", prev, nxt_indx);
+				return IPA_NAT_INVALID_NAT_ENTRY;
+			}
+		}
+
+		sw_rule->prev_index = prev;
+	}
+
+	/* On collision check for the free entry in expansion table */
+	new_entry = ipa_nati_index_expn_get_free_entry(indx_expn_tbl,
+					tbl_ptr->expn_table_entries);
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == new_entry) {
+		/* Expansion table is full return*/
+		IPAERR("Index expansion table is full\n");
+		IPAERR("Current Table: %d & Expn Entries: %d\n",
+			   tbl_ptr->cur_tbl_cnt, tbl_ptr->cur_expn_tbl_cnt);
+		return IPA_NAT_INVALID_NAT_ENTRY;
+	}
+	new_entry += tbl_ptr->table_entries;
+
+
+	if (sw_rule->prev_index == new_entry) {
+		IPAERR("Error: prev_entry:%d ", sw_rule->prev_index);
+		IPAERR("and new_entry:%d should not be same ", new_entry);
+		IPAERR("infinite loop detected\n");
+		return IPA_NAT_INVALID_NAT_ENTRY;
+	}
+
+	IPADBG("index table entry %d\n", new_entry);
+	return new_entry;
+}
+
+/* returns index expn table entry index */
+uint16_t ipa_nati_index_expn_get_free_entry(
+						struct ipa_nat_indx_tbl_rule *indx_tbl,
+						uint16_t size)
+{
+	int cnt;
+	for (cnt = 1; cnt < size; cnt++) {
+		if (!Read16BitFieldValue(indx_tbl[cnt].tbl_entry_nxt_indx,
+														 INDX_TBL_TBL_ENTRY_FIELD)) {
+			return cnt;
+		}
+	}
+
+	IPAERR("nat index expansion table is full\n");
+	return 0;
+}
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+				nat_table_type tbl_type,
+				uint16_t value,
+				uint32_t offset)
+{
+	struct ipa_ioc_nat_dma_cmd *cmd;
+
+	IPADBG("Updating next index field of table %d on collosion using dma\n", tbl_type);
+	IPADBG("table index: %d, value: %d offset;%d\n", tbl_indx, value, offset);
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)
+	malloc(sizeof(struct ipa_ioc_nat_dma_cmd)+
+				 sizeof(struct ipa_ioc_nat_dma_one));
+	if (NULL == cmd) {
+		IPAERR("unable to allocate memory\n");
+		return;
+	}
+
+	cmd->dma[0].table_index = tbl_indx;
+	cmd->dma[0].base_addr = tbl_type;
+	cmd->dma[0].data = value;
+	cmd->dma[0].offset = offset;
+
+	cmd->entries = 1;
+	if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) {
+		perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+		IPAERR("unable to call dma icotl to update next index\n");
+		IPAERR("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		goto fail;
+	}
+
+fail:
+	free(cmd);
+
+	return;
+}
+
+void ipa_nati_copy_ipv4_rule_to_hw(
+				struct ipa_nat_ip4_table_cache *ipv4_cache,
+				struct ipa_nat_sw_rule *rule,
+				uint16_t entry, uint8_t tbl_index)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	uint16_t prev_entry = rule->prev_index;
+	nat_table_type tbl_type;
+	uint32_t offset = 0;
+
+	if (entry < ipv4_cache->table_entries) {
+		tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+
+		memcpy(&tbl_ptr[entry],
+					 rule,
+					 sizeof(struct ipa_nat_rule));
+	} else {
+		tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_expn_rules_addr;
+		memcpy(&tbl_ptr[entry - ipv4_cache->table_entries],
+					 rule,
+					 sizeof(struct ipa_nat_rule));
+	}
+
+	/* Update the previos entry next_index */
+	if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry) {
+
+		if (prev_entry < ipv4_cache->table_entries) {
+			tbl_type = IPA_NAT_BASE_TBL;
+			tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+		} else {
+			tbl_type = IPA_NAT_EXPN_TBL;
+			/* tbp_ptr is already pointing to expansion table
+				 no need to initialize it */
+			prev_entry = prev_entry - ipv4_cache->table_entries;
+		}
+
+		offset = ipa_nati_get_entry_offset(ipv4_cache, tbl_type, prev_entry);
+		offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+
+		ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+	}
+
+	return;
+}
+
+void ipa_nati_copy_ipv4_index_rule_to_hw(
+				struct ipa_nat_ip4_table_cache *ipv4_cache,
+				struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule,
+				uint16_t entry,
+				uint8_t tbl_index)
+{
+	struct ipa_nat_indx_tbl_rule *tbl_ptr;
+	struct ipa_nat_sw_indx_tbl_rule sw_rule;
+	uint16_t prev_entry = indx_sw_rule->prev_index;
+	nat_table_type tbl_type;
+	uint16_t offset = 0;
+
+	sw_rule.next_index = indx_sw_rule->next_index;
+	sw_rule.tbl_entry = indx_sw_rule->tbl_entry;
+
+	if (entry < ipv4_cache->table_entries) {
+		tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+
+		memcpy(&tbl_ptr[entry],
+					 &sw_rule,
+					 sizeof(struct ipa_nat_indx_tbl_rule));
+	} else {
+		tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_expn_addr;
+
+		memcpy(&tbl_ptr[entry - ipv4_cache->table_entries],
+					 &sw_rule,
+					 sizeof(struct ipa_nat_indx_tbl_rule));
+	}
+
+	/* Update the next field of previous entry on collosion */
+	if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry) {
+		if (prev_entry < ipv4_cache->table_entries) {
+			tbl_type = IPA_NAT_INDX_TBL;
+			tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+		} else {
+			tbl_type = IPA_NAT_INDEX_EXPN_TBL;
+			/* tbp_ptr is already pointing to expansion table
+			 no need to initialize it */
+			prev_entry = prev_entry - ipv4_cache->table_entries;
+		}
+
+		offset = ipa_nati_get_index_entry_offset(ipv4_cache, tbl_type, prev_entry);
+		offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+
+		IPADBG("Updating next index field of index table on collosion using dma()\n");
+		ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+	}
+
+	return;
+}
+
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+				uint16_t entry)
+{
+	struct ipa_ioc_nat_dma_cmd *cmd;
+	struct ipa_nat_rule *tbl_ptr;
+	uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_indx].tbl_addr_offset;
+	int ret = 0;
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)
+	malloc(sizeof(struct ipa_ioc_nat_dma_cmd)+
+				 sizeof(struct ipa_ioc_nat_dma_one));
+	if (NULL == cmd) {
+		IPAERR("unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	if (entry < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries) {
+		tbl_ptr =
+			 (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+		cmd->dma[0].table_index = tbl_indx;
+		cmd->dma[0].base_addr = IPA_NAT_BASE_TBL;
+		cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+
+		cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+		cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+	} else {
+		tbl_ptr =
+			 (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr;
+		entry = entry - ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+
+		cmd->dma[0].table_index = tbl_indx;
+		cmd->dma[0].base_addr = IPA_NAT_EXPN_TBL;
+		cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+
+		cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+		cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+		cmd->dma[0].offset += offset;
+	}
+
+	cmd->entries = 1;
+	if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) {
+		perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+		IPAERR("unable to call dma icotl\n");
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		ret = -EIO;
+		goto fail;
+	}
+	IPADBG("posted IPA_IOC_NAT_DMA to kernel successfully during add operation\n");
+
+
+fail:
+	free(cmd);
+
+	return ret;
+}
+
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+				uint32_t rule_hdl)
+{
+	uint8_t expn_tbl;
+	uint16_t tbl_entry;
+	struct ipa_nat_ip4_table_cache *tbl_ptr;
+	del_type rule_pos;
+	uint8_t tbl_indx = (uint8_t)(tbl_hdl - 1);
+
+	/* 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 -EINVAL;
+	}
+
+	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 -EINVAL;
+	}
+
+	ipa_nati_find_rule_pos(tbl_ptr, expn_tbl,
+												 tbl_entry, &rule_pos);
+	IPADBG("rule_pos:%d\n", rule_pos);
+
+	if (ipa_nati_post_del_dma_cmd(tbl_indx, tbl_entry,
+					expn_tbl, rule_pos)) {
+		return -EINVAL;
+	}
+
+	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++) {
+		tmp->dma[cnt1] = cmd->dma[cnt];
+		cnt1++;
+	}
+
+	for (cnt = 0; cnt < indx_tbl_start; cnt++) {
+		tmp->dma[cnt1] = cmd->dma[cnt];
+		cnt1++;
+	}
+
+	memset(cmd, 0, size);
+	memcpy(cmd, tmp, size);
+	free(tmp);
+
+	return;
+}
+
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+				uint16_t cur_tbl_entry,
+				uint8_t expn_tbl,
+				del_type rule_pos)
+{
+
+#define MAX_DMA_ENTRIES_FOR_DEL 3
+
+	struct ipa_nat_ip4_table_cache *cache_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	struct ipa_nat_rule *tbl_ptr;
+	int ret = 0, size = 0;
+
+	uint16_t indx_tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	del_type indx_rule_pos;
+
+	struct ipa_ioc_nat_dma_cmd *cmd;
+	uint8_t no_of_cmds = 0;
+
+	uint16_t prev_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t next_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t indx_next_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t indx_next_next_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t table_entry;
+
+	size = sizeof(struct ipa_ioc_nat_dma_cmd)+
+	(MAX_DMA_ENTRIES_FOR_DEL * sizeof(struct ipa_ioc_nat_dma_one));
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)malloc(size);
+	if (NULL == cmd) {
+		IPAERR("unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	cache_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx];
+	if (!expn_tbl) {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+	} else {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+	}
+
+
+	if (!Read16BitFieldValue(tbl_ptr[cur_tbl_entry].ip_cksm_enbl,
+													 ENABLE_FIELD)) {
+		IPAERR("Deleting invalid(not enabled) rule\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	indx_tbl_entry =
+		Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+		SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD);
+
+	/* ================================================
+	 Base Table rule Deletion
+	 ================================================*/
+	/* Just delete the current rule by disabling the flag field */
+	if (IPA_NAT_DEL_TYPE_ONLY_ONE == rule_pos) {
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		cmd->dma[no_of_cmds].data = IPA_NAT_FLAG_DISABLE_BIT_MASK;
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_entry_offset(cache_ptr,
+					cmd->dma[no_of_cmds].base_addr,
+					cur_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+	}
+
+	/* Just update the protocol field to invalid */
+	else if (IPA_NAT_DEL_TYPE_HEAD == rule_pos) {
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_PROTO_FIELD_VALUE;
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_entry_offset(cache_ptr,
+					cmd->dma[no_of_cmds].base_addr,
+					cur_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_PROTO_FIELD_OFFSET;
+
+		IPADBG("writing invalid proto: 0x%x\n", cmd->dma[no_of_cmds].data);
+	}
+
+	/*
+			 Update the previous entry of next_index field value
+			 with current entry next_index field value
+	*/
+	else if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos) {
+		prev_entry =
+			Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+				SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data =
+			Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+					NEXT_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		if (prev_entry >= cache_ptr->table_entries) {
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_entry_offset(cache_ptr,
+				cmd->dma[no_of_cmds].base_addr, prev_entry);
+
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/*
+			 Reset the previous entry of next_index field with 0
+	*/
+	else if (IPA_NAT_DEL_TYPE_LAST == rule_pos) {
+		prev_entry =
+			Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+				SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		if (prev_entry >= cache_ptr->table_entries) {
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_entry_offset(cache_ptr,
+				cmd->dma[no_of_cmds].base_addr, prev_entry);
+
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* ================================================
+	 Base Table rule Deletion End
+	 ================================================*/
+
+	/* ================================================
+	 Index Table rule Deletion
+	 ================================================*/
+	ipa_nati_find_index_rule_pos(cache_ptr,
+															 indx_tbl_entry,
+															 &indx_rule_pos);
+	IPADBG("Index table entry: 0x%x\n", indx_tbl_entry);
+	IPADBG("and position: %d\n", indx_rule_pos);
+	if (indx_tbl_entry >= cache_ptr->table_entries) {
+		indx_tbl_entry -= cache_ptr->table_entries;
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+	} else {
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+	}
+
+	/* Just delete the current rule by resetting nat_table_index field to 0 */
+	if (IPA_NAT_DEL_TYPE_ONLY_ONE == indx_rule_pos) {
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_index_entry_offset(cache_ptr,
+			cmd->dma[no_of_cmds].base_addr,
+			indx_tbl_entry);
+
+		cmd->dma[no_of_cmds].offset +=
+			IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+	}
+
+	/* copy the next entry values to current entry */
+	else if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos) {
+		next_entry =
+			Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+				INDX_TBL_NEXT_INDEX_FILED);
+
+		next_entry -= cache_ptr->table_entries;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+
+		/* Copy the nat_table_index field value of next entry */
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+		cmd->dma[no_of_cmds].data =
+			Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+				INDX_TBL_TBL_ENTRY_FIELD);
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_index_entry_offset(cache_ptr,
+					cmd->dma[no_of_cmds].base_addr,
+					indx_tbl_entry);
+
+		cmd->dma[no_of_cmds].offset +=
+			IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+
+		/* Copy the next_index field value of next entry */
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data =
+			Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+				INDX_TBL_NEXT_INDEX_FILED);
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_index_entry_offset(cache_ptr,
+				cmd->dma[no_of_cmds].base_addr, indx_tbl_entry);
+
+		cmd->dma[no_of_cmds].offset +=
+			IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+		indx_next_entry = next_entry;
+	}
+
+	/*
+			 Update the previous entry of next_index field value
+			 with current entry next_index field value
+	*/
+	else if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos) {
+		prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data =
+			Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+				INDX_TBL_NEXT_INDEX_FILED);
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		if (prev_entry >= cache_ptr->table_entries) {
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		IPADBG("prev_entry: %d update with cur next_index: %d\n",
+				prev_entry, cmd->dma[no_of_cmds].data);
+		IPADBG("prev_entry: %d exist in table_type:%d\n",
+				prev_entry, cmd->dma[no_of_cmds].base_addr);
+
+		cmd->dma[no_of_cmds].offset =
+			ipa_nati_get_index_entry_offset(cache_ptr,
+				cmd->dma[no_of_cmds].base_addr, prev_entry);
+
+		cmd->dma[no_of_cmds].offset +=
+			IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* Reset the previous entry next_index field with 0 */
+	else if (IPA_NAT_DEL_TYPE_LAST == indx_rule_pos) {
+		prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		if (prev_entry >= cache_ptr->table_entries) {
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		IPADBG("Reseting prev_entry: %d next_index\n", prev_entry);
+		IPADBG("prev_entry: %d exist in table_type:%d\n",
+			prev_entry, cmd->dma[no_of_cmds].base_addr);
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_index_entry_offset(cache_ptr,
+					cmd->dma[no_of_cmds].base_addr, prev_entry);
+
+		cmd->dma[no_of_cmds].offset +=
+			IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* ================================================
+	 Index Table rule Deletion End
+	 ================================================*/
+	cmd->entries = no_of_cmds + 1;
+
+	if (cmd->entries > 1) {
+		ReorderCmds(cmd, size);
+	}
+	if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) {
+		perror("ipa_nati_post_del_dma_cmd(): ioctl error value");
+		IPAERR("unable to post cmd\n");
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		ret = -EIO;
+		goto fail;
+	}
+
+	/* if entry exist in IPA_NAT_DEL_TYPE_MIDDLE of list
+			 Update the previous entry in sw specific parameters
+	*/
+	if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos) {
+		/* Retrieve the current entry prev_entry value */
+		prev_entry =
+			Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+				SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		/* Retrieve the next entry */
+		next_entry =
+			Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+				NEXT_INDEX_FIELD);
+
+		next_entry -= cache_ptr->table_entries;
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+
+		/* copy the current entry prev_entry value to next entry*/
+		UpdateSwSpecParams(&tbl_ptr[next_entry],
+											 IPA_NAT_SW_PARAM_PREV_INDX_BYTE,
+											 prev_entry);
+	}
+
+	/* Reset the other field values of current delete entry
+			 In case of IPA_NAT_DEL_TYPE_HEAD, don't reset */
+	if (IPA_NAT_DEL_TYPE_HEAD != rule_pos) {
+		memset(&tbl_ptr[cur_tbl_entry], 0, sizeof(struct ipa_nat_rule));
+	}
+
+	if (indx_rule_pos == IPA_NAT_DEL_TYPE_HEAD) {
+
+    /* Update next next entry previous value to current
+       entry as we moved the next entry values
+       to current entry */
+		indx_next_next_entry =
+			Read16BitFieldValue(indx_tbl_ptr[indx_next_entry].tbl_entry_nxt_indx,
+				INDX_TBL_NEXT_INDEX_FILED);
+
+		if (indx_next_next_entry != 0 &&
+			indx_next_next_entry >= cache_ptr->table_entries) {
+
+			IPADBG("Next Next entry: %d\n", indx_next_next_entry);
+			indx_next_next_entry -= cache_ptr->table_entries;
+
+			IPADBG("Updating entry: %d prev index to: %d\n",
+				indx_next_next_entry, indx_tbl_entry);
+			cache_ptr->index_expn_table_meta[indx_next_next_entry].prev_index =
+				 indx_tbl_entry;
+		}
+
+    /* Now reset the next entry as we copied
+				the next entry to current entry */
+		IPADBG("Resetting, index table entry(Proper): %d\n",
+			(cache_ptr->table_entries + indx_next_entry));
+
+    /* This resets both table entry and next index values */
+		indx_tbl_ptr[indx_next_entry].tbl_entry_nxt_indx = 0;
+
+		/*
+				 In case of IPA_NAT_DEL_TYPE_HEAD, update the sw specific parameters
+				 (index table entry) of base table entry
+		*/
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+		table_entry =
+				Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+						INDX_TBL_TBL_ENTRY_FIELD);
+
+		if (table_entry >= cache_ptr->table_entries) {
+			tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+			table_entry -= cache_ptr->table_entries;
+		} else {
+			tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+		}
+
+		UpdateSwSpecParams(&tbl_ptr[table_entry],
+				IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE,
+				indx_tbl_entry);
+	} else {
+		/* Update the prev_entry value (in index_expn_table_meta)
+				 for the next_entry in list with current entry prev_entry value
+		*/
+		if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos) {
+			next_entry =
+				Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+					INDX_TBL_NEXT_INDEX_FILED);
+
+			if (next_entry >= cache_ptr->table_entries) {
+				next_entry -= cache_ptr->table_entries;
+			}
+
+			cache_ptr->index_expn_table_meta[next_entry].prev_index =
+				 cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+			cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index =
+				 IPA_NAT_INVALID_NAT_ENTRY;
+		}
+
+		IPADBG("At, indx_tbl_entry value: %d\n", indx_tbl_entry);
+		IPADBG("At, indx_tbl_entry member address: %p\n",
+					 &indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx);
+
+		indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx = 0;
+
+	}
+
+fail:
+	free(cmd);
+
+	return ret;
+}
+
+void ipa_nati_find_index_rule_pos(
+				struct ipa_nat_ip4_table_cache *cache_ptr,
+				uint16_t tbl_entry,
+				del_type *rule_pos)
+{
+	struct ipa_nat_indx_tbl_rule *tbl_ptr;
+
+	if (tbl_entry >= cache_ptr->table_entries) {
+		tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+
+		tbl_entry -= cache_ptr->table_entries;
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+					INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) {
+			*rule_pos = IPA_NAT_DEL_TYPE_LAST;
+		} else {
+			*rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+		}
+	} else {
+		tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+					INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) {
+			*rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+		} else {
+			*rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+		}
+	}
+}
+
+void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr,
+														uint8_t expn_tbl,
+														uint16_t tbl_entry,
+														del_type *rule_pos)
+{
+	struct ipa_nat_rule *tbl_ptr;
+
+	if (expn_tbl) {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+														NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) {
+			*rule_pos = IPA_NAT_DEL_TYPE_LAST;
+		} else {
+			*rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+		}
+	} else {
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+					NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) {
+			*rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+		} else {
+			*rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+		}
+	}
+}
+
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	uint16_t cnt;
+
+	tbl_ptr =
+	(struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+	for (cnt = 0;
+			 cnt < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+			 cnt++) {
+
+		if (Read8BitFieldValue(tbl_ptr[cnt].ts_proto,
+					PROTOCOL_FIELD) == IPA_NAT_INVALID_PROTO_FIELD_CMP
+				&&
+				Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+					NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) {
+			/* Delete the IPA_NAT_DEL_TYPE_HEAD node */
+			IPADBG("deleting the dead node 0x%x\n", cnt);
+			memset(&tbl_ptr[cnt], 0, sizeof(struct ipa_nat_rule));
+		}
+	} /* end of for loop */
+
+	return;
+}
+
+
+/* ========================================================
+						Debug functions
+	 ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	int cnt;
+	uint8_t atl_one = 0;
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+			tbl_hdl > IPA_NAT_MAX_IP4_TBLS) {
+		IPAERR("invalid table handle passed\n");
+		return;
+	}
+
+	/* Print ipv4 rules */
+	IPADBG("Dumping ipv4 active rules:\n");
+	tbl_ptr = (struct ipa_nat_rule *)
+	ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_rules_addr;
+	for (cnt = 0;
+			 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+			 cnt++) {
+		if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+					ENABLE_FIELD)) {
+			atl_one = 1;
+			ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+		}
+	}
+	if (!atl_one) {
+		IPADBG("No active base rules, total: %d\n",
+					 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries);
+	}
+	atl_one = 0;
+
+	/* Print ipv4 expansion rules */
+	IPADBG("Dumping ipv4 active expansion rules:\n");
+	tbl_ptr = (struct ipa_nat_rule *)
+	ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_expn_rules_addr;
+	for (cnt = 0;
+			 cnt <= ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries;
+			 cnt++) {
+		if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+					ENABLE_FIELD)) {
+			atl_one = 1;
+			ipa_nati_print_rule(&tbl_ptr[cnt],
+				(cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries));
+		}
+	}
+	if (!atl_one) {
+		IPADBG("No active base expansion rules, total: %d\n",
+					 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries);
+	}
+	atl_one = 0;
+
+	/* Print ipv4 index rules */
+	IPADBG("Dumping ipv4 index active rules:\n");
+	indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+	ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_addr;
+	for (cnt = 0;
+			 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+			 cnt++) {
+		if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+					INDX_TBL_TBL_ENTRY_FIELD)) {
+			atl_one = 1;
+			ipa_nati_print_index_rule(&indx_tbl_ptr[cnt], cnt, 0);
+		}
+	}
+	if (!atl_one) {
+		IPADBG("No active index table rules, total:%d\n",
+					 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries);
+	}
+	atl_one = 0;
+
+
+	/* Print ipv4 index expansion rules */
+	IPADBG("Dumping ipv4 index expansion active rules:\n");
+	indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+	ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_expn_addr;
+	for (cnt = 0;
+			 cnt <= ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries;
+			 cnt++) {
+		if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+					INDX_TBL_TBL_ENTRY_FIELD)) {
+			atl_one = 1;
+			ipa_nati_print_index_rule(&indx_tbl_ptr[cnt],
+				(cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries),
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_expn_table_meta[cnt].prev_index);
+		}
+	}
+	if (!atl_one) {
+		IPADBG("No active index expansion rules, total:%d\n",
+					 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries);
+	}
+	atl_one = 0;
+
+}
+
+void ipa_nati_print_rule(
+		struct ipa_nat_rule *param,
+		uint32_t rule_id)
+{
+	struct ipa_nat_sw_rule sw_rule;
+	memcpy(&sw_rule, param, sizeof(sw_rule));
+	uint32_t ip_addr;
+
+	IPADUMP("rule-id:%d  ", rule_id);
+	ip_addr = sw_rule.target_ip;
+	IPADUMP("Trgt-IP:%d.%d.%d.%d	",
+				((ip_addr & 0xFF000000) >> 24), ((ip_addr & 0x00FF0000) >> 16),
+			((ip_addr & 0x0000FF00) >> 8), ((ip_addr & 0x000000FF)));
+
+	IPADUMP("Trgt-Port:%d  Priv-Port:%d  ", sw_rule.target_port, sw_rule.private_port);
+
+	ip_addr = sw_rule.private_ip;
+	IPADUMP("Priv-IP:%d.%d.%d.%d ",
+							((ip_addr & 0xFF000000) >> 24), ((ip_addr & 0x00FF0000) >> 16),
+							((ip_addr & 0x0000FF00) >> 8), ((ip_addr & 0x000000FF)));
+
+	IPADUMP("Pub-Port:%d	Nxt-indx:%d  ", sw_rule.public_port, sw_rule.next_index);
+	IPADUMP("IP-cksm-delta:0x%x  En-bit:0x%x	", sw_rule.ip_chksum, sw_rule.enable);
+	IPADUMP("TS:0x%x	Proto:0x%x	", sw_rule.time_stamp, sw_rule.protocol);
+	IPADUMP("Prv-indx:%d	indx_tbl_entry:%d	", sw_rule.prev_index, sw_rule.indx_tbl_entry);
+	IPADUMP("Tcp-udp-cksum-delta:0x%x", sw_rule.tcp_udp_chksum);
+	IPADUMP("\n");
+	return;
+}
+
+void ipa_nati_print_index_rule(
+		struct ipa_nat_indx_tbl_rule *param,
+		uint32_t rule_id, uint16_t prev_indx)
+{
+	struct ipa_nat_sw_indx_tbl_rule sw_rule;
+	memcpy(&sw_rule, param, sizeof(sw_rule));
+
+	IPADUMP("rule-id:%d  Table_entry:%d  Next_index:%d, prev_indx:%d",
+					  rule_id, sw_rule.tbl_entry, sw_rule.next_index, prev_indx);
+	IPADUMP("\n");
+	return;
+}
+
+int ipa_nati_query_nat_rules(
+		uint32_t tbl_hdl,
+		nat_table_type tbl_type)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	int cnt = 0, ret = 0;
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+			tbl_hdl > IPA_NAT_MAX_IP4_TBLS) {
+		IPAERR("invalid table handle passed\n");
+		return ret;
+	}
+
+	/* Print ipv4 rules */
+	if (tbl_type == IPA_NAT_BASE_TBL) {
+		IPADBG("Counting ipv4 active rules:\n");
+		tbl_ptr = (struct ipa_nat_rule *)
+			 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].ipv4_rules_addr;
+		for (cnt = 0;
+				 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+				 cnt++) {
+			if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+						ENABLE_FIELD)) {
+				ret++;
+			}
+		}
+		if (!ret) {
+			IPADBG("No active base rules\n");
+		}
+
+		IPADBG("Number of active base rules: %d\n", ret);
+	}
+
+	/* Print ipv4 expansion rules */
+	if (tbl_type == IPA_NAT_EXPN_TBL) {
+		IPADBG("Counting ipv4 active expansion rules:\n");
+		tbl_ptr = (struct ipa_nat_rule *)
+			 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].ipv4_expn_rules_addr;
+		for (cnt = 0;
+				 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries;
+				 cnt++) {
+			if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+						ENABLE_FIELD)) {
+				ret++;
+			}
+		}
+		if (!ret) {
+			IPADBG("No active base expansion rules\n");
+		}
+
+		IPADBG("Number of active base expansion rules: %d\n", ret);
+	}
+
+	/* Print ipv4 index rules */
+	if (tbl_type == IPA_NAT_INDX_TBL) {
+		IPADBG("Counting ipv4 index active rules:\n");
+		indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+			 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].index_table_addr;
+		for (cnt = 0;
+				 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+				 cnt++) {
+			if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+						INDX_TBL_TBL_ENTRY_FIELD)) {
+				ret++;
+			}
+		}
+		if (!ret) {
+			IPADBG("No active index table rules\n");
+		}
+
+		IPADBG("Number of active index table rules: %d\n", ret);
+	}
+
+	/* Print ipv4 index expansion rules */
+	if (tbl_type == IPA_NAT_INDEX_EXPN_TBL) {
+		IPADBG("Counting ipv4 index expansion active rules:\n");
+		indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+			 ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].index_table_expn_addr;
+		for (cnt = 0;
+				 cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries;
+				 cnt++) {
+			if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+						INDX_TBL_TBL_ENTRY_FIELD)) {
+						ret++;
+			}
+		}
+
+		if (!ret)
+			IPADBG("No active index expansion rules\n");
+
+		IPADBG("Number of active index expansion rules: %d\n", ret);
+	}
+
+	return ret;
+}
+#endif
diff --git a/ipanat/src/ipa_nat_logi.c b/ipanat/src/ipa_nat_logi.c
new file mode 100644
index 0000000..b829b78
--- /dev/null
+++ b/ipanat/src/ipa_nat_logi.c
@@ -0,0 +1,49 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_log.cpp
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include "ipa_nat_logi.h"
+#include <stdlib.h>
+#include <unistd.h>
+
+void log_nat_message(char *msg)
+{
+	 return;
+}
+
+
diff --git a/ipanat/test/Android.mk b/ipanat/test/Android.mk
new file mode 100644
index 0000000..4c94b56
--- /dev/null
+++ b/ipanat/test/Android.mk
@@ -0,0 +1,53 @@
+BOARD_PLATFORM_LIST := msm8916
+BOARD_PLATFORM_LIST += msm8909
+ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
+ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH)))
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ipanat/inc
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_MODULE := ipa_nat_test
+LOCAL_SRC_FILES := ipa_nat_test000.c \
+		ipa_nat_test001.c \
+		ipa_nat_test002.c \
+		ipa_nat_test003.c \
+		ipa_nat_test004.c \
+		ipa_nat_test005.c \
+		ipa_nat_test006.c \
+		ipa_nat_test007.c \
+		ipa_nat_test008.c \
+		ipa_nat_test009.c \
+		ipa_nat_test010.c \
+		ipa_nat_test011.c \
+		ipa_nat_test012.c \
+		ipa_nat_test013.c \
+		ipa_nat_test014.c \
+		ipa_nat_test015.c \
+		ipa_nat_test016.c \
+		ipa_nat_test017.c \
+		ipa_nat_test018.c \
+		ipa_nat_test019.c \
+		ipa_nat_test020.c \
+		ipa_nat_test021.c \
+		ipa_nat_test022.c \
+		main.c
+
+
+LOCAL_SHARED_LIBRARIES := libipanat
+
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/ip_accelerator
+
+include $(BUILD_EXECUTABLE)
+
+endif # $(TARGET_ARCH)
+endif
+endif
\ No newline at end of file
diff --git a/ipanat/test/Makefile.am b/ipanat/test/Makefile.am
new file mode 100644
index 0000000..3aec070
--- /dev/null
+++ b/ipanat/test/Makefile.am
@@ -0,0 +1,42 @@
+AM_CPPFLAGS = -I./../inc \
+	      -I$(top_srcdir)/ipanat/inc
+
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+AM_CPPFLAGS += -g
+
+ipanattest_SOURCES = ipa_nat_test000.c \
+		ipa_nat_test001.c \
+		ipa_nat_test002.c \
+		ipa_nat_test003.c \
+		ipa_nat_test004.c \
+		ipa_nat_test005.c \
+		ipa_nat_test006.c \
+		ipa_nat_test007.c \
+		ipa_nat_test008.c \
+		ipa_nat_test009.c \
+		ipa_nat_test010.c \
+		ipa_nat_test011.c \
+		ipa_nat_test012.c \
+		ipa_nat_test013.c \
+		ipa_nat_test014.c \
+		ipa_nat_test015.c \
+		ipa_nat_test016.c \
+		ipa_nat_test017.c \
+		ipa_nat_test018.c \
+		ipa_nat_test019.c \
+		ipa_nat_test020.c \
+		ipa_nat_test021.c \
+		ipa_nat_test022.c \
+		main.c
+
+
+bin_PROGRAMS  =  ipanattest
+
+requiredlibs =  ../src/libipanat.la
+
+ipanattest_LDADD =  $(requiredlibs)
+
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/ipanat/test/README.txt b/ipanat/test/README.txt
new file mode 100644
index 0000000..4e87121
--- /dev/null
+++ b/ipanat/test/README.txt
@@ -0,0 +1,18 @@
+1 To run this suite separately(each test case creates table and delete table) use below command
+   - To execute test suite nt times with n entries, command "ipanatest sep nt n"
+
+  Example:  To execute test suite 1 time with 100 entries, command "ipanattest sep 100"
+
+
+2. To run test suite not separately(creates table and delete table only once) use below command
+   - To execute test suite nt times with n entries, command "ipanatest reg nt n"
+
+   Example: To execute test suite 5 times with 32 entries, command "ipanattest reg 5 32"
+
+
+3. To run inotify regression test use command, "ipanattest inotify nt"
+
+   Example: To execute inotify 5 times, command "ipanattest inotify 5"
+
+
+4. if we just give command "ipanattest", runs test suite 1 time with 100 entries (non separate)
diff --git a/ipanat/test/ipa_nat_test.h b/ipanat/test/ipa_nat_test.h
new file mode 100644
index 0000000..d5ac0d5
--- /dev/null
+++ b/ipanat/test/ipa_nat_test.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, 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 FILES FOR MODULE
+
+===========================================================================*/
+#include "stdint.h"  /* uint32_t */
+#include "stdio.h"
+#include <netinet/in.h> /* for proto definitions */
+
+#define u32 uint32_t
+#define u16 uint16_t
+#define u8  uint8_t
+
+/*============ Preconditions to run NAT Test cases =========*/
+#define IPA_NAT_TEST_PRE_COND_TE  20
+
+#define CHECK_ERR1(x, tbl_hdl) \
+  if(ipa_nat_validate_ipv4_table(tbl_hdl)) { \
+    if(sep) {\
+       ipa_nat_del_ipv4_tbl(tbl_hdl); \
+     }\
+    return -1;\
+  }\
+  if(x) { \
+    IPAERR("%d\n", ret); \
+    if(sep) {\
+      ipa_nat_del_ipv4_tbl(tbl_hdl); \
+     }\
+     return -1; \
+  }
+
+#define CHECK_ERR(x) if(x) { \
+    IPAERR("%d\n", ret); \
+    return -1;\
+ }
+
+#if 0
+#define CHECK_ERR(x) if(x) { \
+    IPAERR("%d\n", ret); \
+    if(sep) {\
+      ipa_nat_del_ipv4_tbl(tbl_hdl); \
+    }\
+    return -1;\
+ }
+#endif
+
+#define IPADBG(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+#define IPAERR(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+
+#define NAT_DUMP
+int ipa_nat_validate_ipv4_table(u32);
+
+int ipa_nat_test000(int, u32, u8);
+int ipa_nat_test001(int, u32, u8);
+int ipa_nat_test002(int, u32, u8);
+int ipa_nat_test003(int, u32, u8);
+int ipa_nat_test004(int, u32, u8);
+int ipa_nat_test005(int, u32, u8);
+int ipa_nat_test006(int, u32, u8);
+int ipa_nat_test007(int, u32, u8);
+int ipa_nat_test008(int, u32, u8);
+int ipa_nat_test009(int, u32, u8);
+int ipa_nat_test010(int, u32, u8);
+int ipa_nat_test011(int, u32, u8);
+int ipa_nat_test012(int, u32, u8);
+int ipa_nat_test013(int, u32, u8);
+int ipa_nat_test014(int, u32, u8);
+int ipa_nat_test015(int, u32, u8);
+int ipa_nat_test016(int, u32, u8);
+int ipa_nat_test017(int, u32, u8);
+int ipa_nat_test018(int, u32, u8);
+int ipa_nat_test019(int, u32, u8);
+int ipa_nat_test020(int, u32, u8);
+int ipa_nat_test021(int, int);
+int ipa_nat_test022(int, u32, u8);
diff --git a/ipanat/test/ipa_nat_test000.c b/ipanat/test/ipa_nat_test000.c
new file mode 100644
index 0000000..09914ea
--- /dev/null
+++ b/ipanat/test/ipa_nat_test000.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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_test000.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Delete ipv4 table
+*/
+/*===========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test000(int total_entries, u32 tbl_hdl, u8 sep)
+{
+
+	int ret;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+	if (0 != ret)
+	{
+		IPAERR("unable to create ipv4 nat table and returning Error:%d\n", ret);
+		return -1;
+	}
+	IPADBG("create nat ipv4 table successfully() \n");
+
+	IPADBG("calling ipa_nat_del_ipv4_tbl() \n");
+	ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+	if (0 != ret)
+	{
+		IPAERR("Unable to delete ipv4 nat table %d\n", ret);
+		return -1;
+	}
+	IPADBG("deleted ipv4 nat table successfully. Test passed \n");
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test001.c b/ipanat/test/ipa_nat_test001.c
new file mode 100644
index 0000000..8daef33
--- /dev/null
+++ b/ipanat/test/ipa_nat_test001.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 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_test001.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Add ipv4 rule
+	3. Delete ipv4 table
+*/
+/*===========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test001(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s()\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test002.c b/ipanat/test/ipa_nat_test002.c
new file mode 100644
index 0000000..e6f5ae3
--- /dev/null
+++ b/ipanat/test/ipa_nat_test002.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, 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_test002.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Add ipv4 rule
+	3. delete ipv4 rule
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test002(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s()\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test003.c b/ipanat/test/ipa_nat_test003.c
new file mode 100644
index 0000000..0634265
--- /dev/null
+++ b/ipanat/test/ipa_nat_test003.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 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_ipa_nat_test003.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Add ipv4 rule
+	3. Add ipv4 rule
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test003(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test004.c b/ipanat/test/ipa_nat_test004.c
new file mode 100644
index 0000000..02378ff
--- /dev/null
+++ b/ipanat/test/ipa_nat_test004.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 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_test004.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Query nat table handle
+	3. Delete ipv4 table
+*/
+/*===========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test004(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret = 0;
+	u32 tbl_hdl1 = 0;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl1);
+		if(ret == 0)
+		{
+			IPAERR("able to delete table using invalid table handle\n");
+			return -1;
+		}
+	}
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test005.c b/ipanat/test/ipa_nat_test005.c
new file mode 100644
index 0000000..12228d1
--- /dev/null
+++ b/ipanat/test/ipa_nat_test005.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, 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_test005.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Add ipv4 rule
+	3. Delete ipv4 rule
+	4. Add ipv4 rule
+	5. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test005(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret = 0;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	if (sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+		CHECK_ERR(ret);
+
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test006.c b/ipanat/test/ipa_nat_test006.c
new file mode 100644
index 0000000..36f0171
--- /dev/null
+++ b/ipanat/test/ipa_nat_test006.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014, 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_test006.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same ipv rules
+	3. delete first followed by second
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test006(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret=0;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test007.c b/ipanat/test/ipa_nat_test007.c
new file mode 100644
index 0000000..4160c02
--- /dev/null
+++ b/ipanat/test/ipa_nat_test007.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, 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_test007.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same ipv rules
+	3. delete second followed by first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test007(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test008.c b/ipanat/test/ipa_nat_test008.c
new file mode 100644
index 0000000..d016055
--- /dev/null
+++ b/ipanat/test/ipa_nat_test008.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 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_test008.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 2 distinct rules
+	3. delete first followed by second
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test008(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+	ipv4_rule1.target_ip = 0xC1171602; /* 193.23.22.2 */
+	ipv4_rule1.target_port = 1234;
+	ipv4_rule1.private_ip = 0xC2171602; /* 194.23.22.2 */
+	ipv4_rule1.private_port = 5678;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test009.c b/ipanat/test/ipa_nat_test009.c
new file mode 100644
index 0000000..cf3c40f
--- /dev/null
+++ b/ipanat/test/ipa_nat_test009.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 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_test009.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 2 distinct rules
+	3. delete second followed by first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test009(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	ipv4_rule1.target_ip = 0xC1171602; /* 193.23.22.2 */
+	ipv4_rule1.target_port = 1234;
+	ipv4_rule1.private_ip = 0xC2171602; /* 194.23.22.2 */
+	ipv4_rule1.private_port = 5678;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test010.c b/ipanat/test/ipa_nat_test010.c
new file mode 100644
index 0000000..42d7fee
--- /dev/null
+++ b/ipanat/test/ipa_nat_test010.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 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_test010.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 3 distinct ipv4 rules
+	3. delete first, second followed by last
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test010(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1, rule_hdl2;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1, ipv4_rule2;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	ipv4_rule1.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule1.target_port = 1235;
+	ipv4_rule1.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule1.private_port = 5679;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 9051;
+
+	ipv4_rule2.target_ip = 0xC1171602; /* 193.23.22.2 */
+	ipv4_rule2.target_port = 1235;
+	ipv4_rule2.private_ip = 0xC2171602; /* 194.23.22.2 */
+	ipv4_rule2.private_port = 5679;
+	ipv4_rule2.protocol = IPPROTO_TCP;
+	ipv4_rule2.public_port = 9051;
+
+	IPADBG("%s():\n",__FUNCTION__);
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test011.c b/ipanat/test/ipa_nat_test011.c
new file mode 100644
index 0000000..bcce76c
--- /dev/null
+++ b/ipanat/test/ipa_nat_test011.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 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_test011.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 3 distinct ipv4 rules
+	3. delete second, first followed by last
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test011(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1, rule_hdl2;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1, ipv4_rule2;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	ipv4_rule1.target_ip = 0xF1181601;
+	ipv4_rule1.target_port = 1555;
+	ipv4_rule1.private_ip = 0xF2151601;
+	ipv4_rule1.private_port = 5999;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 9111;
+
+	ipv4_rule2.target_ip = 0xC1166602;
+	ipv4_rule2.target_port = 1555;
+	ipv4_rule2.private_ip = 0xC2155602;
+	ipv4_rule2.private_port = 5777;
+	ipv4_rule2.protocol = IPPROTO_TCP;
+	ipv4_rule2.public_port = 9000;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test012.c b/ipanat/test/ipa_nat_test012.c
new file mode 100644
index 0000000..9d3c835
--- /dev/null
+++ b/ipanat/test/ipa_nat_test012.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, 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_test012.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 3 distinct ipv4 rules
+	3. Delete third, second, first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+
+int ipa_nat_test012(int totoal_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1, rule_hdl2;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1, ipv4_rule2;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	ipv4_rule1.target_ip = 0xD1171601;
+	ipv4_rule1.target_port = 3512;
+	ipv4_rule1.private_ip = 0xD2471601;
+	ipv4_rule1.private_port = 9997;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 8881;
+
+	ipv4_rule2.target_ip = 0xC1172452;
+	ipv4_rule2.target_port = 1895;
+	ipv4_rule2.private_ip = 0xC2172452;
+	ipv4_rule2.private_port = 6668;
+	ipv4_rule2.protocol = IPPROTO_TCP;
+	ipv4_rule2.public_port = 5551;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, totoal_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test013.c b/ipanat/test/ipa_nat_test013.c
new file mode 100644
index 0000000..2b9b005
--- /dev/null
+++ b/ipanat/test/ipa_nat_test013.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 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_test013.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add 3 distinct ipv4 rules
+	3. Delete third, first and second
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test013(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl, rule_hdl1, rule_hdl2;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule1, ipv4_rule2;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	ipv4_rule1.target_ip = 0xC1171609; /* 193.23.22.9 */
+	ipv4_rule1.target_port = 1235;
+	ipv4_rule1.private_ip = 0xC2171609; /* 194.23.22.9 */
+	ipv4_rule1.private_port = 6579;
+	ipv4_rule1.protocol = IPPROTO_TCP;
+	ipv4_rule1.public_port = 8951;
+
+	ipv4_rule2.target_ip = 0xC1171606; /* 193.23.22.6 */
+	ipv4_rule2.target_port = 1235;
+	ipv4_rule2.private_ip = 0xC2171606; /* 194.23.22.6 */
+	ipv4_rule2.private_port = 7956;
+	ipv4_rule2.protocol = IPPROTO_TCP;
+	ipv4_rule2.public_port = 5109;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule1, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test014.c b/ipanat/test/ipa_nat_test014.c
new file mode 100644
index 0000000..fd30317
--- /dev/null
+++ b/ipanat/test/ipa_nat_test014.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 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_test014.cpp
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete first, second and third
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test014(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s()\n", __FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test015.c b/ipanat/test/ipa_nat_test015.c
new file mode 100644
index 0000000..eaef923
--- /dev/null
+++ b/ipanat/test/ipa_nat_test015.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 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_test015.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete first, third and second
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+
+int ipa_nat_test015(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test016.c b/ipanat/test/ipa_nat_test016.c
new file mode 100644
index 0000000..23157e2
--- /dev/null
+++ b/ipanat/test/ipa_nat_test016.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 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_test016.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete second, first and third
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test016(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test017.c b/ipanat/test/ipa_nat_test017.c
new file mode 100644
index 0000000..d88e611
--- /dev/null
+++ b/ipanat/test/ipa_nat_test017.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 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_test017.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete second, third and first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test017(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test018.c b/ipanat/test/ipa_nat_test018.c
new file mode 100644
index 0000000..c885d4d
--- /dev/null
+++ b/ipanat/test/ipa_nat_test018.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 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_test018.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete third, second and first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test018(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test019.c b/ipanat/test/ipa_nat_test019.c
new file mode 100644
index 0000000..3ba3119
--- /dev/null
+++ b/ipanat/test/ipa_nat_test019.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 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_test019.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+	3. delete third, first and second
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test019(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test020.c b/ipanat/test/ipa_nat_test020.c
new file mode 100644
index 0000000..e6871b5
--- /dev/null
+++ b/ipanat/test/ipa_nat_test020.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 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_test020.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 4 ipv rules
+	3. delete third, second, fourth and first
+	4. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test020(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3, rule_hdl4;
+	ipa_nat_ipv4_rule ipv4_rule;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl4);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl2);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl4);
+	CHECK_ERR(ret);
+
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR(ret);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR(ret);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test021.c b/ipanat/test/ipa_nat_test021.c
new file mode 100644
index 0000000..48c4321
--- /dev/null
+++ b/ipanat/test/ipa_nat_test021.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, 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_test021.c
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test021(int total_entries, int reg)
+{
+
+	int ret, i;
+	u32 tbl_hdl;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	for(i=0; i<reg; i++)
+	{
+		IPADBG("executing %d th time:\n",i);
+
+		IPADBG("calling ipa_nat_add_ipv4_tbl() \n");
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		if (0 != ret)
+		{
+			IPAERR("unable to create ipv4 nat table and returning Error:%d\n", ret);
+			IPADBG("executed %d times:\n",i);
+			return -1;
+		}
+		IPADBG("create nat ipv4 table successfully() \n");
+
+		IPADBG("calling ipa_nat_del_ipv4_tbl() \n");
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		if (0 != ret)
+		{
+			IPAERR("Unable to delete ipv4 nat table %d\n", ret);
+			IPADBG("executed %d times:\n",i);
+			return -1;
+		}
+		IPADBG("deleted ipv4 nat table successfully. Test passed \n");
+	}
+
+	IPADBG("executed %d times:\n",(i+1));
+	return 0;
+}
diff --git a/ipanat/test/ipa_nat_test022.c b/ipanat/test/ipa_nat_test022.c
new file mode 100644
index 0000000..ebdd291
--- /dev/null
+++ b/ipanat/test/ipa_nat_test022.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014, 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_test022.cpp
+
+	@brief
+	Verify the following scenario:
+	1. Add ipv4 table
+	2. add same 3 ipv rules
+  3. delete Head and last entry
+  4. add 2 new same ip4 entries
+  5. Add head entry again
+	6. Delete ipv4 table
+*/
+/*=========================================================================*/
+
+#include "ipa_nat_test.h"
+#include "ipa_nat_drv.h"
+
+int ipa_nat_test022(int total_entries, u32 tbl_hdl, u8 sep)
+{
+	int ret;
+	u32 rule_hdl1, rule_hdl2, rule_hdl3;
+	ipa_nat_ipv4_rule ipv4_rule, ipv4_rule2;
+	u32 rule_hdl21, rule_hdl22;
+
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	/* Rule 1 */
+	ipv4_rule.target_ip = 0xC1171601; /* 193.23.22.1 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171601; /* 194.23.22.1 */
+	ipv4_rule.private_port = 5678;
+	ipv4_rule.protocol = IPPROTO_TCP;
+	ipv4_rule.public_port = 9050;
+
+	/* Rule 2*/
+	ipv4_rule.target_ip = 0xC1171604; /* 193.23.22.4 */
+	ipv4_rule.target_port = 1234;
+	ipv4_rule.private_ip = 0xC2171603; /* 194.23.22.3 */
+	ipv4_rule.private_port = 5680;
+	ipv4_rule.protocol = IPPROTO_UDP;
+	ipv4_rule.public_port = 9066;
+
+	IPADBG("%s():\n",__FUNCTION__);
+
+	if(sep)
+	{
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+		CHECK_ERR1(ret, tbl_hdl);
+	}
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl1);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl2);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	/* Delete head entry */
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl1);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	/* Delete Last Entry */
+	ret = ipa_nat_del_ipv4_rule(tbl_hdl, rule_hdl3);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	/* Add 2 different Entries */
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl21);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule2, &rule_hdl22);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	/* Add first entry again */
+	ret = ipa_nat_add_ipv4_rule(tbl_hdl, &ipv4_rule, &rule_hdl3);
+	CHECK_ERR1(ret, tbl_hdl);
+
+	if(sep)
+	{
+		ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+		CHECK_ERR1(ret, tbl_hdl);
+	}
+
+	return 0;
+}
diff --git a/ipanat/test/main.c b/ipanat/test/main.c
new file mode 100644
index 0000000..c49ce3b
--- /dev/null
+++ b/ipanat/test/main.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2014, 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+#include "ipa_nat_test.h"
+
+extern struct ipa_nat_cache ipv4_nat_cache;
+
+int chk_for_loop(u32 tbl_hdl)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	int cnt;
+	uint16_t cur_entry;
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+			tbl_hdl > IPA_NAT_MAX_IP4_TBLS) {
+		IPAERR("invalid table handle passed \n");
+		return -EINVAL;
+	}
+
+	IPADBG("checking ipv4 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)) {
+			if(Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+							NEXT_INDEX_FIELD) == cnt)
+			{
+				IPAERR("Infinite loop detected, entry\n");
+				ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* Print ipv4 expansion rules */
+	IPADBG("checking 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)) {
+			cur_entry =
+				cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+			if (Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+							NEXT_INDEX_FIELD) == cur_entry)
+			{
+				IPAERR("Infinite loop detected\n");
+				ipa_nati_print_rule(&tbl_ptr[cnt],
+					(cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries));
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* Print ipv4 index rules */
+	IPADBG("checking 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)) {
+			if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+							INDX_TBL_NEXT_INDEX_FILED) == cnt)
+			{
+				IPAERR("Infinite loop detected\n");
+				ipa_nati_print_index_rule(&indx_tbl_ptr[cnt], cnt, 0);
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* Print ipv4 index expansion rules */
+	IPADBG("Checking 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)) {
+			cur_entry =
+				cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+			if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+							INDX_TBL_NEXT_INDEX_FILED) == cur_entry)
+			{
+				IPAERR("Infinite loop detected\n");
+				ipa_nati_print_index_rule(&indx_tbl_ptr[cnt],
+					(cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries),
+				ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].index_expn_table_meta[cnt].prev_index);
+				return -EINVAL;
+			}
+		}
+	}
+	return 0;
+}
+
+uint8_t is_base_entry_valid(u32 tbl_hdl, u16 entry)
+{
+	struct ipa_nat_rule *tbl_ptr;
+
+	if (entry >
+		ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries)
+	{
+		tbl_ptr = (struct ipa_nat_rule *)
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_expn_rules_addr;
+		entry -=
+			ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+	}
+	else
+	{
+		tbl_ptr = (struct ipa_nat_rule *)
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_rules_addr;
+	}
+	return (Read16BitFieldValue(tbl_ptr[entry].ip_cksm_enbl,
+							ENABLE_FIELD));
+}
+
+uint8_t is_index_entry_valid(u32 tbl_hdl, u16 entry)
+{
+	struct ipa_nat_indx_tbl_rule *tbl_ptr;
+
+	if (entry >
+		ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries)
+	{
+		tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_expn_addr;
+		entry -=
+			ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries;
+	}
+	else
+	{
+		tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_addr;
+	}
+	if (Read16BitFieldValue(tbl_ptr[entry].tbl_entry_nxt_indx,
+						INDX_TBL_TBL_ENTRY_FIELD)) {
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+int chk_for_validity(u32 tbl_hdl)
+{
+	struct ipa_nat_rule *tbl_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	uint16_t nxt_index, prv_index;
+	int cnt;
+
+	if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+			tbl_hdl > IPA_NAT_MAX_IP4_TBLS) {
+		IPAERR("invalid table handle passed \n");
+		return -EINVAL;
+	}
+
+	/* Validate base table next_indx and prev_indx values */
+	IPADBG("Validating 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)) {
+			nxt_index =
+			Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+						NEXT_INDEX_FIELD);
+			if (!is_base_entry_valid(tbl_hdl, nxt_index)) {
+				IPAERR("Invalid next index found, entry:%d\n", cnt);
+			}
+		}
+	}
+
+	IPADBG("Validating ipv4 expansion active 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)) {
+			/* Validate next index */
+			nxt_index =
+				Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+									NEXT_INDEX_FIELD);
+			if (!is_base_entry_valid(tbl_hdl, nxt_index)) {
+				IPAERR("Invalid next index found, entry:%d\n", cnt);
+			}
+			/* Validate previous index */
+			prv_index =
+				Read16BitFieldValue(tbl_ptr[cnt].sw_spec_params,
+						SW_SPEC_PARAM_PREV_INDEX_FIELD);
+			if (!is_base_entry_valid(tbl_hdl, prv_index)) {
+				IPAERR("Invalid Previous index found, entry:%d\n", cnt);
+			}
+		}
+	}
+
+	IPADBG("Validating 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)) {
+			nxt_index =
+				Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+							INDX_TBL_NEXT_INDEX_FILED);
+			if (!is_index_entry_valid(tbl_hdl, nxt_index)) {
+				IPAERR("Invalid next index found, entry:%d\n", cnt);
+			}
+		}
+	}
+
+	IPADBG("Validating 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)) {
+			/* Validate next index*/
+			nxt_index =
+				Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+								INDX_TBL_NEXT_INDEX_FILED);
+			if (!is_index_entry_valid(tbl_hdl, nxt_index)) {
+				IPAERR("Invalid next index found, entry:%d\n", cnt);
+			}
+
+			/* Validate previous index*/
+			prv_index =
+				ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_expn_table_meta[cnt].prev_index;
+
+			if (!is_index_entry_valid(tbl_hdl, prv_index)) {
+				IPAERR("Invalid Previous index found, entry:%d\n", cnt);
+			}
+		}
+	}
+
+	return 0;
+}
+
+int ipa_nat_validate_ipv4_table(u32 tbl_hdl)
+{
+	int ret = 0;
+
+	ret = chk_for_loop(tbl_hdl);
+	if (ret)
+		return ret;
+	ret = chk_for_validity(tbl_hdl);
+
+	return ret;
+}
+
+int main(int argc, char* argv[])
+{
+	int exec = 0, pass = 0, ret;
+	int cnt, nt=1;
+	int total_entries = 100;
+	u8 sep = 0;
+	u32 tbl_hdl = 0;
+	u32 pub_ip_add = 0x011617c0;   /* "192.23.22.1" */
+
+	IPADBG("ipa_nat_testing user space nat driver\n");
+
+	if (argc == 4)
+	{
+		if (!strncmp(argv[1], "reg", 3))
+		{
+			nt = atoi(argv[2]);
+			total_entries = atoi(argv[3]);
+			IPADBG("Reg: %d, Nat Entries: %d\n", nt, total_entries);
+		}
+		else if (!strncmp(argv[1], "sep", 3))
+		{
+			sep = 1;
+			nt = atoi(argv[2]);
+			total_entries = atoi(argv[3]);
+		}
+	}
+	else if (argc == 3)
+	{
+		if (!strncmp(argv[1], "inotify", 7))
+		{
+			ipa_nat_test021(total_entries, atoi(argv[2]));
+			return 0;
+		}
+		else if (!strncmp(argv[1], "sep", 3))
+		{
+			sep = 1;
+			total_entries = atoi(argv[2]);
+		}
+	}
+	else if (argc == 2)
+	{
+		total_entries = atoi(argv[1]);
+		IPADBG("Nat Entries: %d\n", total_entries);
+	}
+
+
+	for (cnt=0; cnt<nt; cnt++)
+	{
+		IPADBG("%s():Executing %d time \n",__FUNCTION__, cnt);
+
+		if (!sep)
+		{
+			ret = ipa_nat_add_ipv4_tbl(pub_ip_add, total_entries, &tbl_hdl);
+			CHECK_ERR(ret);
+		}
+
+		if (sep)
+		{
+			IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+			ret = ipa_nat_test000(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test00%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+			ret = ipa_nat_test001(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test00%d Fail\n", exec);
+			}
+			exec++;
+		}
+
+		IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+		ret = ipa_nat_test002(total_entries, tbl_hdl, sep);
+		if (!ret)
+		{
+			pass++;
+		}
+		else
+		{
+			IPAERR("ipa_nat_test00%d Fail\n", exec);
+		}
+		exec++;
+
+		if (sep)
+		{
+			IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+			ret = ipa_nat_test003(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test00%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+			ret = ipa_nat_test004(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test00%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+			ret = ipa_nat_test005(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test00%d Fail\n", exec);
+			}
+			exec++;
+		}
+
+		IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+		ret = ipa_nat_test006(total_entries, tbl_hdl, sep);
+		if (!ret)
+		{
+			pass++;
+		}
+		else
+		{
+			IPAERR("ipa_nat_test00%d Fail\n", exec);
+		}
+		exec++;
+
+		IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+		ret = ipa_nat_test007(total_entries, tbl_hdl, sep);
+		if (!ret)
+		{
+			pass++;
+		}
+		else
+		{
+			IPAERR("ipa_nat_test00%d Fail\n", exec);
+		}
+		exec++;
+
+		IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+		ret = ipa_nat_test008(total_entries, tbl_hdl, sep);
+		if (!ret)
+		{
+			pass++;
+		}
+		else
+		{
+			IPAERR("ipa_nat_test00%d Fail\n", exec);
+		}
+		exec++;
+
+		IPADBG("\n\nExecuting ipa_nat_test00%d\n", exec);
+		ret = ipa_nat_test009(total_entries, tbl_hdl, sep);
+		if (!ret)
+		{
+			pass++;
+		}
+		else
+		{
+			IPAERR("ipa_nat_test00%d Fail\n", exec);
+		}
+		exec++;
+
+		if (total_entries >= IPA_NAT_TEST_PRE_COND_TE)
+		{
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test010(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test011(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test012(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test013(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test014(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test015(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test016(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test017(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test018(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test019(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test020(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+
+			IPADBG("\n\nExecuting ipa_nat_test0%d\n", exec);
+			ret = ipa_nat_test022(total_entries, tbl_hdl, sep);
+			if (!ret)
+			{
+				pass++;
+			}
+			else
+			{
+				IPAERR("ipa_nat_test0%d Fail\n", exec);
+			}
+			exec++;
+		}
+
+		if (!sep)
+		{
+			ret = ipa_nat_del_ipv4_tbl(tbl_hdl);
+			CHECK_ERR(ret);
+		}
+	}
+	/*=======  Printing Results ==========*/
+	IPADBG("Total ipa_nat Tests Run:%d, Pass:%d, Fail:%d\n",exec, pass, exec-pass);
+	return 0;
+}