Home | History | Annotate | Download | only in src
      1 /*
      2 Copyright (c) 2017, The Linux Foundation. All rights reserved.
      3 
      4 Redistribution and use in source and binary forms, with or without
      5 modification, are permitted provided that the following conditions are
      6 met:
      7 * Redistributions of source code must retain the above copyright
      8   notice, this list of conditions and the following disclaimer.
      9 * Redistributions in binary form must reproduce the above
     10   copyright notice, this list of conditions and the following
     11   disclaimer in the documentation and/or other materials provided
     12   with the distribution.
     13 * Neither the name of The Linux Foundation nor the names of its
     14   contributors may be used to endorse or promote products derived
     15   from this software without specific prior written permission.
     16 
     17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.Z
     28 */
     29 /*!
     30   @file
     31   IPACM_OffloadManager.cpp
     32 
     33   @brief
     34   This file implements the basis Iface functionality.
     35 
     36   @Author
     37   Skylar Chang
     38 
     39 */
     40 #include <IPACM_OffloadManager.h>
     41 #include <sys/ioctl.h>
     42 #include <net/if.h>
     43 #include <string.h>
     44 #include "IPACM_ConntrackClient.h"
     45 #include "IPACM_ConntrackListener.h"
     46 #include "IPACM_Iface.h"
     47 #include "IPACM_Config.h"
     48 #include <unistd.h>
     49 
     50 const char *IPACM_OffloadManager::DEVICE_NAME = "/dev/wwan_ioctl";
     51 
     52 /* NatApp class Implementation */
     53 IPACM_OffloadManager *IPACM_OffloadManager::pInstance = NULL;
     54 
     55 IPACM_OffloadManager::IPACM_OffloadManager()
     56 {
     57 	default_gw_index = INVALID_IFACE;
     58 	upstream_v4_up = false;
     59 	upstream_v6_up = false;
     60 	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
     61 	latest_cache_index = 0;
     62 	return ;
     63 }
     64 
     65 RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener)
     66 {
     67 	RET result = SUCCESS;
     68 	if (elrInstance == NULL) {
     69 		IPACMDBG_H("get registerEventListener \n");
     70 		elrInstance = eventlistener;
     71 	} else {
     72 		IPACMDBG_H("already have EventListener previously, override \n");
     73 		elrInstance = eventlistener;
     74 		result = FAIL_INPUT_CHECK;
     75 	}
     76 	return SUCCESS;
     77 }
     78 
     79 RET IPACM_OffloadManager::unregisterEventListener(IpaEventListener* )
     80 {
     81 	RET result = SUCCESS;
     82 	if (elrInstance)
     83 		elrInstance = NULL;
     84 	else {
     85 		IPACMDBG_H("already unregisterEventListener previously \n");
     86 		result = SUCCESS_DUPLICATE_CONFIG;
     87 	}
     88 	return SUCCESS;
     89 }
     90 
     91 RET IPACM_OffloadManager::registerCtTimeoutUpdater(ConntrackTimeoutUpdater* timeoutupdater)
     92 {
     93 	RET result = SUCCESS;
     94 	if (touInstance == NULL)
     95 	{
     96 		IPACMDBG_H("get ConntrackTimeoutUpdater \n");
     97 		touInstance = timeoutupdater;
     98 	} else {
     99 		IPACMDBG_H("already have ConntrackTimeoutUpdater previously, override \n");
    100 		touInstance = timeoutupdater;
    101 		result = FAIL_INPUT_CHECK;
    102 	}
    103 	return SUCCESS;
    104 }
    105 
    106 RET IPACM_OffloadManager::unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* )
    107 {
    108 	RET result = SUCCESS;
    109 	if (touInstance)
    110 		touInstance = NULL;
    111 	else {
    112 		IPACMDBG_H("already unregisterCtTimeoutUpdater previously \n");
    113 		result = SUCCESS_DUPLICATE_CONFIG;
    114 	}
    115 	return SUCCESS;
    116 }
    117 
    118 RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups)
    119 {
    120 	IPACM_ConntrackClient *cc;
    121 	int on = 1, rel;
    122 	struct sockaddr_nl	local;
    123 	unsigned int addr_len;
    124 
    125 	cc = IPACM_ConntrackClient::GetInstance();
    126 
    127 	if(!cc)
    128 	{
    129 		IPACMERR("Init failed: cc %p\n", cc);
    130 		return FAIL_HARDWARE;
    131 	}
    132 
    133 	/* check socket name */
    134 	memset(&local, 0, sizeof(struct sockaddr_nl));
    135 	addr_len = sizeof(local);
    136 	getsockname(fd, (struct sockaddr *)&local, &addr_len);
    137 	IPACMDBG_H(" FD %d, nl_pad %d nl_pid %u\n", fd, local.nl_pad, local.nl_pid);
    138 
    139 	/* add the check if getting FDs already or not */
    140 	if(cc->fd_tcp > -1 && cc->fd_udp > -1) {
    141 		IPACMDBG_H("has valid FDs fd_tcp %d, fd_udp %d, ignore fd %d.\n", cc->fd_tcp, cc->fd_udp, fd);
    142 		return SUCCESS;
    143 	}
    144 
    145 	if (groups == cc->subscrips_tcp) {
    146 		cc->fd_tcp = dup(fd);
    147 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
    148 		/* set netlink buf */
    149 		rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
    150 		if (rel == -1)
    151 		{
    152 			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
    153 		}
    154 	} else if (groups == cc->subscrips_udp) {
    155 		cc->fd_udp = dup(fd);
    156 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
    157 		/* set netlink buf */
    158 		rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
    159 		if (rel == -1)
    160 		{
    161 			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
    162 		}
    163 	} else {
    164 		IPACMERR("Received unexpected fd with groups %d.\n", groups);
    165 	}
    166 	if(cc->fd_tcp >0 && cc->fd_udp >0) {
    167 		IPACMDBG_H(" Got both fds from framework, start conntrack listener thread.\n");
    168 		CtList->CreateConnTrackThreads();
    169 	}
    170 	return SUCCESS;
    171 }
    172 
    173 RET IPACM_OffloadManager::clearAllFds()
    174 {
    175 
    176 	/* IPACM needs to kee old FDs, can't clear */
    177 	IPACMDBG_H("Still use old Fds, can't clear \n");
    178 	return SUCCESS;
    179 }
    180 
    181 bool IPACM_OffloadManager::isStaApSupported()
    182 {
    183 	return true;
    184 }
    185 
    186 
    187 RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */)
    188 {
    189 	return SUCCESS;
    190 }
    191 
    192 RET IPACM_OffloadManager::addDownstream(const char * downstream_name, const Prefix &prefix)
    193 {
    194 	int index;
    195 	ipacm_cmd_q_data evt;
    196 	ipacm_event_ipahal_stream *evt_data;
    197 
    198 	IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
    199 
    200 	if (prefix.fam == V4) {
    201 		IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask);
    202 	} else {
    203 		IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n",
    204 							prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]);
    205 		IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n",
    206 							prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]);
    207 	}
    208 
    209 	/* check if netdev valid on device */
    210 	if(ipa_get_if_index(downstream_name, &index))
    211 	{
    212 		IPACMERR("fail to get iface index.\n");
    213 		return FAIL_INPUT_CHECK;
    214 	}
    215 	/* Iface is valid, add to list if not present */
    216 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
    217 	{
    218 		/* Iface is new, add it to the list */
    219 		valid_ifaces.push_back(downstream_name);
    220 		IPACMDBG_H("add iface(%s) to list\n", downstream_name);
    221 	}
    222 
    223 	/* check if downstream netdev driver finished its configuration on IPA-HW */
    224 	if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name))
    225 	{
    226 		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
    227 		/* copy to the cache */
    228 		for(int i = 0; i < MAX_EVENT_CACHE ;i++)
    229 		{
    230 			if(event_cache[latest_cache_index].valid == false)
    231 			{
    232 				//do the copy
    233 				event_cache[latest_cache_index].valid = true;
    234 				event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
    235 				memcpy(event_cache[latest_cache_index].dev_name, downstream_name, sizeof(event_cache[latest_cache_index].dev_name));
    236 				memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix, sizeof(event_cache[latest_cache_index].prefix_cache));
    237 				if (prefix.fam == V4) {
    238 					IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
    239 						event_cache[latest_cache_index].event,
    240 						event_cache[latest_cache_index].prefix_cache.v4Addr,
    241 						event_cache[latest_cache_index].prefix_cache.v4Mask,
    242 						event_cache[latest_cache_index].dev_name,
    243 						latest_cache_index);
    244 				} else {
    245 					IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
    246 						event_cache[latest_cache_index].event,
    247 						event_cache[latest_cache_index].prefix_cache.v6Addr[0],
    248 						event_cache[latest_cache_index].prefix_cache.v6Addr[1],
    249 						event_cache[latest_cache_index].prefix_cache.v6Addr[2],
    250 						event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
    251 					IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n",
    252 						event_cache[latest_cache_index].prefix_cache.v6Mask[0],
    253 						event_cache[latest_cache_index].prefix_cache.v6Mask[1],
    254 						event_cache[latest_cache_index].prefix_cache.v6Mask[2],
    255 						event_cache[latest_cache_index].prefix_cache.v6Mask[3],
    256 						event_cache[latest_cache_index].dev_name,
    257 						latest_cache_index);
    258 				}
    259 				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
    260 				break;
    261 			}
    262 			latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
    263 			if(i == MAX_EVENT_CACHE - 1)
    264 			{
    265 				IPACMDBG_H(" run out of event cache (%d)\n", i);
    266 		return FAIL_HARDWARE;
    267 	}
    268 		}
    269 
    270 		return SUCCESS;
    271 	}
    272 
    273 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
    274 	if(evt_data == NULL)
    275 	{
    276 		IPACMERR("Failed to allocate memory.\n");
    277 		return FAIL_HARDWARE;
    278 	}
    279 	memset(evt_data, 0, sizeof(*evt_data));
    280 
    281 	evt_data->if_index = index;
    282 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
    283 
    284 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
    285 	evt.evt_data = (void*)evt_data;
    286 	evt.event = IPA_DOWNSTREAM_ADD;
    287 
    288 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n");
    289 	IPACM_EvtDispatcher::PostEvt(&evt);
    290 
    291 	return SUCCESS;
    292 }
    293 
    294 RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix)
    295 {
    296 	int index;
    297 	ipacm_cmd_q_data evt;
    298 	ipacm_event_ipahal_stream *evt_data;
    299 
    300 	IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
    301 	if(strnlen(downstream_name, sizeof(downstream_name)) == 0)
    302 	{
    303 		IPACMERR("iface length is 0.\n");
    304 		return FAIL_HARDWARE;
    305 	}
    306 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
    307 	{
    308 		IPACMERR("iface is not present in list.\n");
    309 		return FAIL_HARDWARE;
    310 	}
    311 
    312 	if(ipa_get_if_index(downstream_name, &index))
    313 	{
    314 		IPACMERR("netdev(%s) already removed, ignored\n", downstream_name);
    315 		return SUCCESS;
    316 	}
    317 
    318 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
    319 	if(evt_data == NULL)
    320 	{
    321 		IPACMERR("Failed to allocate memory.\n");
    322 		return FAIL_HARDWARE;
    323 	}
    324 	memset(evt_data, 0, sizeof(*evt_data));
    325 
    326 	evt_data->if_index = index;
    327 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
    328 
    329 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
    330 	evt.evt_data = (void*)evt_data;
    331 	evt.event = IPA_DOWNSTREAM_DEL;
    332 
    333 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n");
    334 	IPACM_EvtDispatcher::PostEvt(&evt);
    335 
    336 	return SUCCESS;
    337 }
    338 
    339 RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6)
    340 {
    341 	int index;
    342 	RET result = SUCCESS;
    343 
    344 	/* if interface name is NULL, default route is removed */
    345 	IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam);
    346 
    347 	if(upstream_name == NULL)
    348 	{
    349 		if (default_gw_index == INVALID_IFACE) {
    350 			IPACMERR("no previous upstream set before\n");
    351 			return FAIL_INPUT_CHECK;
    352 		}
    353 		if (gw_addr_v4.fam == V4 && upstream_v4_up == true) {
    354 			IPACMDBG_H("clean upstream(%s) for ipv4-fam(%d) upstream_v4_up(%d)\n", upstream_name, gw_addr_v4.fam, upstream_v4_up);
    355 			post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
    356 			upstream_v4_up = false;
    357 		}
    358 		if (gw_addr_v6.fam == V6 && upstream_v6_up == true) {
    359 			IPACMDBG_H("clean upstream(%s) for ipv6-fam(%d) upstream_v6_up(%d)\n", upstream_name, gw_addr_v6.fam, upstream_v6_up);
    360 			post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
    361 			upstream_v6_up = false;
    362 		}
    363 		default_gw_index = INVALID_IFACE;
    364 	}
    365 	else
    366 	{
    367 		/* check if netdev valid on device */
    368 		if(ipa_get_if_index(upstream_name, &index))
    369 		{
    370 			IPACMERR("fail to get iface index.\n");
    371 			return FAIL_INPUT_CHECK;
    372 		}
    373 
    374 		/* check if downstream netdev driver finished its configuration on IPA-HW */
    375 		if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name))
    376 		{
    377 			IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
    378 			/* copy to the cache */
    379 			for(int i = 0; i < MAX_EVENT_CACHE ;i++)
    380 			{
    381 				if(event_cache[latest_cache_index].valid == false)
    382 				{
    383 					//do the copy
    384 					event_cache[latest_cache_index].valid = true;
    385 					event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
    386 					memcpy(event_cache[latest_cache_index].dev_name, upstream_name, sizeof(event_cache[latest_cache_index].dev_name));
    387 					memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4, sizeof(event_cache[latest_cache_index].prefix_cache));
    388 					memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6, sizeof(event_cache[latest_cache_index].prefix_cache_v6));
    389 					if (gw_addr_v4.fam == V4) {
    390 						IPACMDBG_H("cache event(%d) ipv4 fateway: (%x) dev(%s) on entry (%d)\n",
    391 							event_cache[latest_cache_index].event,
    392 							event_cache[latest_cache_index].prefix_cache.v4Addr,
    393 							event_cache[latest_cache_index].dev_name,
    394 							latest_cache_index);
    395 		}
    396 
    397 					if (gw_addr_v6.fam == V6)
    398 		{
    399 						IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n",
    400 							event_cache[latest_cache_index].event,
    401 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0],
    402 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1],
    403 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2],
    404 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3],
    405 							event_cache[latest_cache_index].dev_name,
    406 							latest_cache_index);
    407 					}
    408 					latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
    409 					break;
    410 				}
    411 				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
    412 				if(i == MAX_EVENT_CACHE - 1)
    413 				{
    414 					IPACMDBG_H(" run out of event cache (%d) \n", i);
    415 					return FAIL_HARDWARE;
    416 				}
    417 			}
    418 			return SUCCESS;
    419 		}
    420 
    421 		/* reset the stats when switch from LTE->STA */
    422 		if (index != default_gw_index) {
    423 			IPACMDBG_H(" interface switched to %s\n", upstream_name);
    424 			if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0)
    425 			{
    426 				IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n");
    427 				resetTetherStats(upstream_name);
    428 			}
    429 		}
    430 
    431 		if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) {
    432 
    433 			if (upstream_v4_up == false) {
    434 				IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr);
    435 				/* posting route add event for both IPv4 and IPv6 */
    436 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
    437 				upstream_v4_up = true;
    438 			} else {
    439 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
    440 			}
    441 
    442 			if (upstream_v6_up == false) {
    443 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
    444 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
    445 				post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
    446 				upstream_v6_up = true;
    447 			} else {
    448 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
    449 			}
    450 		} else if (gw_addr_v4.fam == V4 ) {
    451 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
    452 			if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) {
    453 				/* clean up previous V6 upstream event */
    454 				IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index);
    455 				post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
    456 				upstream_v6_up = false;
    457 			}
    458 
    459 			if (upstream_v4_up == false) {
    460 				IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr);
    461 				/* posting route add event for both IPv4 and IPv6 */
    462 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
    463 				upstream_v4_up = true;
    464 			} else {
    465 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
    466 				result = SUCCESS_DUPLICATE_CONFIG;
    467 			}
    468 		} else if (gw_addr_v6.fam == V6) {
    469 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
    470 			if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) {
    471 				/* clean up previous V4 upstream event */
    472 				IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index);
    473 				post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
    474 				upstream_v4_up = false;
    475 			}
    476 
    477 			if (upstream_v6_up == false) {
    478 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
    479 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
    480 				post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
    481 				upstream_v6_up = true;
    482 			} else {
    483 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
    484 				result = SUCCESS_DUPLICATE_CONFIG;
    485 			}
    486 		}
    487 		default_gw_index = index;
    488 		IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name);
    489 	}
    490 	return result;
    491 }
    492 
    493 RET IPACM_OffloadManager::stopAllOffload()
    494 {
    495 	Prefix v4gw, v6gw;
    496 	RET result = SUCCESS;
    497 
    498 	memset(&v4gw, 0, sizeof(v4gw));
    499 	memset(&v6gw, 0, sizeof(v6gw));
    500 	v4gw.fam = V4;
    501 	v6gw.fam = V6;
    502 	IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam);
    503 	result = setUpstream(NULL, v4gw, v6gw);
    504 
    505 	/* reset the event cache */
    506 	default_gw_index = INVALID_IFACE;
    507 	upstream_v4_up = false;
    508 	upstream_v6_up = false;
    509 	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
    510 	latest_cache_index = 0;
    511 	valid_ifaces.clear();
    512 	return result;
    513 }
    514 
    515 RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */)
    516 {
    517 	wan_ioctl_set_data_quota quota;
    518 	int fd = -1;
    519 
    520 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0)
    521 	{
    522 		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
    523 		return FAIL_HARDWARE;
    524 	}
    525 
    526 	quota.quota_mbytes = mb;
    527 	quota.set_quota = true;
    528 
    529     memset(quota.interface_name, 0, IFNAMSIZ);
    530     if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
    531 		IPACMERR("String truncation occurred on upstream");
    532 		close(fd);
    533 		return FAIL_INPUT_CHECK;
    534 	}
    535 
    536 	IPACMDBG_H("SET_DATA_QUOTA %s %lu", quota.interface_name, mb);
    537 
    538 	if (ioctl(fd, WAN_IOC_SET_DATA_QUOTA, &quota) < 0) {
    539         IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s", strerror(errno));
    540 		close(fd);
    541 		return FAIL_TRY_AGAIN;
    542 	}
    543 
    544 	close(fd);
    545 	return SUCCESS;
    546 }
    547 
    548 RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */,
    549 		bool reset /* reset */, OffloadStatistics& offload_stats/* ret */)
    550 {
    551 	int fd = -1;
    552 	wan_ioctl_query_tether_stats_all stats;
    553 
    554 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
    555         IPACMERR("Failed opening %s.\n", DEVICE_NAME);
    556         return FAIL_HARDWARE;
    557     }
    558 
    559     memset(&stats, 0, sizeof(stats));
    560     if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
    561 		IPACMERR("String truncation occurred on upstream\n");
    562 		close(fd);
    563 		return FAIL_INPUT_CHECK;
    564 	}
    565 	stats.reset_stats = reset;
    566 	stats.ipa_client = IPACM_CLIENT_MAX;
    567 
    568 	if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) {
    569         IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno));
    570 		close(fd);
    571 		return FAIL_TRY_AGAIN;
    572 	}
    573 	/* feedback to IPAHAL*/
    574 	offload_stats.tx = stats.tx_bytes;
    575 	offload_stats.rx = stats.rx_bytes;
    576 
    577 	IPACMDBG_H("send getStats tx:%lu rx:%lu \n", offload_stats.tx, offload_stats.rx);
    578 	close(fd);
    579 	return SUCCESS;
    580 }
    581 
    582 int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr)
    583 {
    584 	ipacm_cmd_q_data evt;
    585 	ipacm_event_data_iptype *evt_data_route;
    586 
    587 	evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype));
    588 	if(evt_data_route == NULL)
    589 	{
    590 		IPACMERR("Failed to allocate memory.\n");
    591 		return -EFAULT;
    592 	}
    593 	memset(evt_data_route, 0, sizeof(*evt_data_route));
    594 
    595 	evt_data_route->if_index = index;
    596 	evt_data_route->if_index_tether = 0;
    597 	evt_data_route->iptype = iptype;
    598 
    599 #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
    600 	evt_data_route->ipv4_addr_gw = gw_addr.v4Addr;
    601 	evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0];
    602 	evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1];
    603 	evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2];
    604 	evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3];
    605 	IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw);
    606 	IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
    607 					evt_data_route->ipv6_addr_gw[0], evt_data_route->ipv6_addr_gw[1], evt_data_route->ipv6_addr_gw[2], evt_data_route->ipv6_addr_gw[3]);
    608 #endif
    609 	IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
    610 			evt_data_route->if_index_tether, evt_data_route->iptype);
    611 
    612 	memset(&evt, 0, sizeof(evt));
    613 	evt.evt_data = (void*)evt_data_route;
    614 	evt.event = event;
    615 
    616 	IPACM_EvtDispatcher::PostEvt(&evt);
    617 
    618 	return 0;
    619 }
    620 
    621 int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index)
    622 {
    623 	int fd;
    624 	struct ifreq ifr;
    625 
    626 	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    627 	{
    628 		IPACMERR("get interface index socket create failed \n");
    629 		return IPACM_FAILURE;
    630 	}
    631 
    632 	if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) {
    633 		IPACMERR("interface name overflows: len %zu\n", strnlen(if_name, sizeof(if_name)));
    634 		close(fd);
    635 		return IPACM_FAILURE;
    636 	}
    637 
    638 	memset(&ifr, 0, sizeof(struct ifreq));
    639 	(void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
    640 	IPACMDBG_H("interface name (%s)\n", if_name);
    641 
    642 	if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
    643 	{
    644 		IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
    645 		close(fd);
    646 		return IPACM_FAILURE;
    647 	}
    648 
    649 	*if_index = ifr.ifr_ifindex;
    650 	IPACMDBG_H("Interface netdev index %d\n", *if_index);
    651 	close(fd);
    652 	return IPACM_SUCCESS;
    653 }
    654 
    655 int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */)
    656 {
    657 	int fd = -1;
    658 	wan_ioctl_reset_tether_stats stats;
    659 
    660 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
    661         IPACMERR("Failed opening %s.\n", DEVICE_NAME);
    662         return FAIL_HARDWARE;
    663     }
    664 
    665     memset(stats.upstreamIface, 0, IFNAMSIZ);
    666     if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
    667 		IPACMERR("String truncation occurred on upstream\n");
    668 		close(fd);
    669 		return FAIL_INPUT_CHECK;
    670 	}
    671 	stats.reset_stats = true;
    672 
    673 	if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) {
    674         IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
    675 		close(fd);
    676 		return FAIL_HARDWARE;
    677 	}
    678 	IPACMDBG_H("Reset Interface %s stats\n", upstream_name);
    679 	close(fd);
    680 	return IPACM_SUCCESS;
    681 }
    682 
    683 IPACM_OffloadManager* IPACM_OffloadManager::GetInstance()
    684 {
    685 	if(pInstance == NULL)
    686 		pInstance = new IPACM_OffloadManager();
    687 
    688 	return pInstance;
    689 }
    690 
    691 bool IPACM_OffloadManager::search_framwork_cache(char * interface_name)
    692 {
    693 	bool rel = false;
    694 
    695 	/* IPACM needs to kee old FDs, can't clear */
    696 	IPACMDBG_H("check netdev(%s)\n", interface_name);
    697 
    698 	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
    699 	{
    700 		if(event_cache[i].valid == true)
    701 		{
    702 			//do the compare
    703 			if (strncmp(event_cache[i].dev_name,
    704 					interface_name,
    705 					sizeof(event_cache[i].dev_name)) == 0)
    706 			{
    707 				IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event);
    708 				/* post event again */
    709 				if (event_cache[i].event == IPA_DOWNSTREAM_ADD)
    710 					addDownstream(interface_name, event_cache[i].prefix_cache);
    711 				else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT)
    712 					setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6);
    713 				else
    714 					IPACMERR("wrong event cached (%d)", event_cache[i].event);
    715 				event_cache[i].valid = false;
    716 				rel = true;
    717 			}
    718 		}
    719 	}
    720 	IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name);
    721 	return rel;
    722 }
    723