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