1 /*
2 Copyright (c) 2017-2018, 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 	bool cache_need = false;
200 
201 	IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
202 
203 	if (prefix.fam == V4) {
204 		IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask);
205 	} else {
206 		IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n",
207 							prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]);
208 		IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n",
209 							prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]);
210 	}
211 
212 	/* check if netdev valid on device */
213 	if(ipa_get_if_index(downstream_name, &index))
214 	{
215 		IPACMERR("fail to get iface index.\n");
216 		return FAIL_INPUT_CHECK;
217 	}
218 
219 	/* Iface is valid, add to list if not present */
220 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
221 	{
222 		/* Iface is new, add it to the list */
223 		valid_ifaces.push_back(downstream_name);
224 		IPACMDBG_H("add iface(%s) to list\n", downstream_name);
225 	}
226 
227 	/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
228 	if (prefix.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v4))
229 		cache_need = true;
230 	if (prefix.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v6))
231 		cache_need = true;
232 
233 	if (cache_need)
234 	{
235 		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
236 
237 		/* copy to the cache */
238 		for(int i = 0; i < MAX_EVENT_CACHE ;i++)
239 		{
240 			if(event_cache[latest_cache_index].valid == false)
241 			{
242 				//do the copy
243 				event_cache[latest_cache_index].valid = true;
244 				event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
245 				memcpy(event_cache[latest_cache_index].dev_name, downstream_name, sizeof(event_cache[latest_cache_index].dev_name));
246 				memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix, sizeof(event_cache[latest_cache_index].prefix_cache));
247 				if (prefix.fam == V4) {
248 					IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
249 						event_cache[latest_cache_index].event,
250 						event_cache[latest_cache_index].prefix_cache.v4Addr,
251 						event_cache[latest_cache_index].prefix_cache.v4Mask,
252 						event_cache[latest_cache_index].dev_name,
253 						latest_cache_index);
254 				} else {
255 					IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
256 						event_cache[latest_cache_index].event,
257 						event_cache[latest_cache_index].prefix_cache.v6Addr[0],
258 						event_cache[latest_cache_index].prefix_cache.v6Addr[1],
259 						event_cache[latest_cache_index].prefix_cache.v6Addr[2],
260 						event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
261 					IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n",
262 						event_cache[latest_cache_index].prefix_cache.v6Mask[0],
263 						event_cache[latest_cache_index].prefix_cache.v6Mask[1],
264 						event_cache[latest_cache_index].prefix_cache.v6Mask[2],
265 						event_cache[latest_cache_index].prefix_cache.v6Mask[3],
266 						event_cache[latest_cache_index].dev_name,
267 						latest_cache_index);
268 				}
269 				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
270 				break;
271 			}
272 			latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
273 			if(i == MAX_EVENT_CACHE - 1)
274 			{
275 				IPACMDBG_H(" run out of event cache (%d)\n", i);
276 		return FAIL_HARDWARE;
277 	}
278 		}
279 
280 		return SUCCESS;
281 	}
282 
283 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
284 	if(evt_data == NULL)
285 	{
286 		IPACMERR("Failed to allocate memory.\n");
287 		return FAIL_HARDWARE;
288 	}
289 	memset(evt_data, 0, sizeof(*evt_data));
290 
291 	evt_data->if_index = index;
292 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
293 
294 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
295 	evt.evt_data = (void*)evt_data;
296 	evt.event = IPA_DOWNSTREAM_ADD;
297 
298 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n");
299 	IPACM_EvtDispatcher::PostEvt(&evt);
300 
301 	return SUCCESS;
302 }
303 
removeDownstream(const char * downstream_name,const Prefix & prefix)304 RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix)
305 {
306 	int index;
307 	ipacm_cmd_q_data evt;
308 	ipacm_event_ipahal_stream *evt_data;
309 
310 	IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
311 	if(strnlen(downstream_name, sizeof(downstream_name)) == 0)
312 	{
313 		IPACMERR("iface length is 0.\n");
314 		return FAIL_HARDWARE;
315 	}
316 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
317 	{
318 		IPACMERR("iface is not present in list.\n");
319 		return FAIL_HARDWARE;
320 	}
321 
322 	if(ipa_get_if_index(downstream_name, &index))
323 	{
324 		IPACMERR("netdev(%s) already removed, ignored\n", downstream_name);
325 		return SUCCESS;
326 	}
327 
328 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
329 	if(evt_data == NULL)
330 	{
331 		IPACMERR("Failed to allocate memory.\n");
332 		return FAIL_HARDWARE;
333 	}
334 	memset(evt_data, 0, sizeof(*evt_data));
335 
336 	evt_data->if_index = index;
337 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
338 
339 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
340 	evt.evt_data = (void*)evt_data;
341 	evt.event = IPA_DOWNSTREAM_DEL;
342 
343 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n");
344 	IPACM_EvtDispatcher::PostEvt(&evt);
345 
346 	return SUCCESS;
347 }
348 
setUpstream(const char * upstream_name,const Prefix & gw_addr_v4,const Prefix & gw_addr_v6)349 RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6)
350 {
351 	int index;
352 	RET result = SUCCESS;
353 	bool cache_need = false;
354 
355 	/* if interface name is NULL, default route is removed */
356 	if(upstream_name != NULL)
357 	{
358 		IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam);
359 	}
360 	else
361 	{
362 		IPACMDBG_H("setUpstream clean upstream_name for ipv4-fam(%d) ipv6-fam(%d)\n", gw_addr_v4.fam, gw_addr_v6.fam);
363 	}
364 	if(upstream_name == NULL)
365 	{
366 		if (default_gw_index == INVALID_IFACE) {
367 			result = FAIL_INPUT_CHECK;
368 			for (index = 0; index < MAX_EVENT_CACHE; index++) {
369 				if (event_cache[index].valid == true &&
370 					event_cache[index ].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) {
371 					event_cache[index].valid = false;
372 					result = SUCCESS;
373 				}
374 			}
375 			IPACMERR("no previous upstream set before\n");
376 			return result;
377 		}
378 		if (gw_addr_v4.fam == V4 && upstream_v4_up == true) {
379 			IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
380 			post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
381 			upstream_v4_up = false;
382 		}
383 		if (gw_addr_v6.fam == V6 && upstream_v6_up == true) {
384 			IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
385 			post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
386 			upstream_v6_up = false;
387 		}
388 		default_gw_index = INVALID_IFACE;
389 	}
390 	else
391 	{
392 		/* check if netdev valid on device */
393 		if(ipa_get_if_index(upstream_name, &index))
394 		{
395 			IPACMERR("fail to get iface index.\n");
396 			return FAIL_INPUT_CHECK;
397 		}
398 
399 		/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
400 		if (gw_addr_v4.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v4))
401 			cache_need = true;
402 		if (gw_addr_v6.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v6))
403 			cache_need = true;
404 
405 		if (cache_need)
406 		{
407 			IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
408 			/* add ipacm restart support */
409 			push_iface_up(upstream_name, true);
410 
411 			/* copy to the cache */
412 			for(int i = 0; i < MAX_EVENT_CACHE ;i++)
413 			{
414 				if(event_cache[latest_cache_index].valid == false)
415 				{
416 					//do the copy
417 					event_cache[latest_cache_index].valid = true;
418 					event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
419 					memcpy(event_cache[latest_cache_index].dev_name, upstream_name, sizeof(event_cache[latest_cache_index].dev_name));
420 					memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4, sizeof(event_cache[latest_cache_index].prefix_cache));
421 					memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6, sizeof(event_cache[latest_cache_index].prefix_cache_v6));
422 					if (gw_addr_v4.fam == V4) {
423 						IPACMDBG_H("cache event(%d) ipv4 gateway: (%x) dev(%s) on entry (%d)\n",
424 							event_cache[latest_cache_index].event,
425 							event_cache[latest_cache_index].prefix_cache.v4Addr,
426 							event_cache[latest_cache_index].dev_name,
427 							latest_cache_index);
428 		}
429 
430 					if (gw_addr_v6.fam == V6)
431 		{
432 						IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n",
433 							event_cache[latest_cache_index].event,
434 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0],
435 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1],
436 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2],
437 							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3],
438 							event_cache[latest_cache_index].dev_name,
439 							latest_cache_index);
440 					}
441 					latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
442 					break;
443 				}
444 				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
445 				if(i == MAX_EVENT_CACHE - 1)
446 				{
447 					IPACMDBG_H(" run out of event cache (%d) \n", i);
448 					return FAIL_HARDWARE;
449 				}
450 			}
451 			return SUCCESS;
452 		}
453 
454 		/* reset the stats when switch from LTE->STA */
455 		if (index != default_gw_index) {
456 			IPACMDBG_H(" interface switched to %s\n", upstream_name);
457 			if (upstream_v4_up == true) {
458 				IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
459 				post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
460 				upstream_v4_up = false;
461 			}
462 			if (upstream_v6_up == true) {
463 				IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
464 				post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
465 				upstream_v6_up = false;
466 			}
467 			default_gw_index = INVALID_IFACE;
468 			if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0)
469 			{
470 				IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n");
471 				resetTetherStats(upstream_name);
472 			}
473 		}
474 
475 		if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) {
476 
477 			if (upstream_v4_up == false) {
478 				IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr);
479 				/* posting route add event for both IPv4 and IPv6 */
480 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
481 				upstream_v4_up = true;
482 			} else {
483 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
484 			}
485 
486 			if (upstream_v6_up == false) {
487 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
488 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
489 				/* check v6-address valid or not */
490 				if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0))
491 				{
492 					IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
493 				} else {
494 					post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
495 					upstream_v6_up = true;
496 				}
497 			} else {
498 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
499 			}
500 		} else if (gw_addr_v4.fam == V4 ) {
501 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
502 			if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) {
503 				/* clean up previous V6 upstream event */
504 				IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index);
505 				post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
506 				upstream_v6_up = false;
507 			}
508 
509 			if (upstream_v4_up == false) {
510 				IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr);
511 				/* posting route add event for both IPv4 and IPv6 */
512 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
513 				upstream_v4_up = true;
514 			} else {
515 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
516 				result = SUCCESS_DUPLICATE_CONFIG;
517 			}
518 		} else if (gw_addr_v6.fam == V6) {
519 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
520 			if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) {
521 				/* clean up previous V4 upstream event */
522 				IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index);
523 				post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
524 				upstream_v4_up = false;
525 			}
526 
527 			if (upstream_v6_up == false) {
528 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
529 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
530 				/* check v6-address valid or not */
531 				if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0))
532 				{
533 					IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
534 				} else {
535 					post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
536 					upstream_v6_up = true;
537 				}
538 			} else {
539 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
540 				result = SUCCESS_DUPLICATE_CONFIG;
541 			}
542 		}
543 		default_gw_index = index;
544 		IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name);
545 	}
546 	return result;
547 }
548 
stopAllOffload()549 RET IPACM_OffloadManager::stopAllOffload()
550 {
551 	Prefix v4gw, v6gw;
552 	RET result = SUCCESS;
553 
554 	memset(&v4gw, 0, sizeof(v4gw));
555 	memset(&v6gw, 0, sizeof(v6gw));
556 	v4gw.fam = V4;
557 	v6gw.fam = V6;
558 	IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam);
559 	result = setUpstream(NULL, v4gw, v6gw);
560 
561 	/* reset the event cache */
562 	default_gw_index = INVALID_IFACE;
563 	upstream_v4_up = false;
564 	upstream_v6_up = false;
565 	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
566 	latest_cache_index = 0;
567 	valid_ifaces.clear();
568 	return result;
569 }
570 
setQuota(const char * upstream_name,uint64_t mb)571 RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */)
572 {
573 	wan_ioctl_set_data_quota quota;
574 	int fd = -1, rc = 0, err_type = 0;
575 
576 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0)
577 	{
578 		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
579 		return FAIL_HARDWARE;
580 	}
581 
582 	quota.quota_mbytes = mb;
583 	quota.set_quota = true;
584 
585     memset(quota.interface_name, 0, IFNAMSIZ);
586     if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
587 		IPACMERR("String truncation occurred on upstream");
588 		close(fd);
589 		return FAIL_INPUT_CHECK;
590 	}
591 
592 	IPACMDBG_H("SET_DATA_QUOTA %s %lu", quota.interface_name, mb);
593 
594 	rc = ioctl(fd, WAN_IOC_SET_DATA_QUOTA, &quota);
595 
596 	if(rc != 0)
597 	{
598 		err_type = errno;
599 		close(fd);
600 		IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s err_type: %d\n", strerror(err_type), err_type);
601 		if (err_type == ENODEV) {
602 			IPACMDBG_H("Invalid argument.\n");
603 			return FAIL_UNSUPPORTED;
604 		}
605 		else {
606 			return FAIL_TRY_AGAIN;
607 		}
608 	}
609 	close(fd);
610 	return SUCCESS;
611 }
612 
getStats(const char * upstream_name,bool reset,OffloadStatistics & offload_stats)613 RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */,
614 		bool reset /* reset */, OffloadStatistics& offload_stats/* ret */)
615 {
616 	int fd = -1;
617 	wan_ioctl_query_tether_stats_all stats;
618 
619 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
620         IPACMERR("Failed opening %s.\n", DEVICE_NAME);
621         return FAIL_HARDWARE;
622     }
623 
624     memset(&stats, 0, sizeof(stats));
625     if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
626 		IPACMERR("String truncation occurred on upstream\n");
627 		close(fd);
628 		return FAIL_INPUT_CHECK;
629 	}
630 	stats.reset_stats = reset;
631 	stats.ipa_client = IPACM_CLIENT_MAX;
632 
633 	if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) {
634         IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno));
635 		close(fd);
636 		return FAIL_TRY_AGAIN;
637 	}
638 	/* feedback to IPAHAL*/
639 	offload_stats.tx = stats.tx_bytes;
640 	offload_stats.rx = stats.rx_bytes;
641 
642 	IPACMDBG_H("send getStats tx:%lu rx:%lu \n", offload_stats.tx, offload_stats.rx);
643 	close(fd);
644 	return SUCCESS;
645 }
646 
post_route_evt(enum ipa_ip_type iptype,int index,ipa_cm_event_id event,const Prefix & gw_addr)647 int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr)
648 {
649 	ipacm_cmd_q_data evt;
650 	ipacm_event_data_iptype *evt_data_route;
651 
652 	evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype));
653 	if(evt_data_route == NULL)
654 	{
655 		IPACMERR("Failed to allocate memory.\n");
656 		return -EFAULT;
657 	}
658 	memset(evt_data_route, 0, sizeof(*evt_data_route));
659 
660 	evt_data_route->if_index = index;
661 	evt_data_route->if_index_tether = 0;
662 	evt_data_route->iptype = iptype;
663 
664 #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
665 	evt_data_route->ipv4_addr_gw = gw_addr.v4Addr;
666 	evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0];
667 	evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1];
668 	evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2];
669 	evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3];
670 	IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw);
671 	IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
672 					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]);
673 #endif
674 	if (event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) {
675 		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
676 			evt_data_route->if_index_tether, evt_data_route->iptype);
677 	}
678 	else if (event == IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT) {
679 		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) tether_fid(%d) ip-type(%d)\n",
680 				evt_data_route->if_index,
681 				evt_data_route->if_index_tether, evt_data_route->iptype);
682 	}
683 	memset(&evt, 0, sizeof(evt));
684 	evt.evt_data = (void*)evt_data_route;
685 	evt.event = event;
686 
687 	IPACM_EvtDispatcher::PostEvt(&evt);
688 
689 	return 0;
690 }
691 
ipa_get_if_index(const char * if_name,int * if_index)692 int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index)
693 {
694 	int fd;
695 	struct ifreq ifr;
696 
697 	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
698 	{
699 		IPACMERR("get interface index socket create failed \n");
700 		return IPACM_FAILURE;
701 	}
702 
703 	if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) {
704 		IPACMERR("interface name overflows: len %zu\n", strnlen(if_name, sizeof(if_name)));
705 		close(fd);
706 		return IPACM_FAILURE;
707 	}
708 
709 	memset(&ifr, 0, sizeof(struct ifreq));
710 	(void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
711 	IPACMDBG_H("interface name (%s)\n", if_name);
712 
713 	if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
714 	{
715 		IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
716 		close(fd);
717 		return IPACM_FAILURE;
718 	}
719 
720 	*if_index = ifr.ifr_ifindex;
721 	IPACMDBG_H("Interface netdev index %d\n", *if_index);
722 	close(fd);
723 	return IPACM_SUCCESS;
724 }
725 
resetTetherStats(const char * upstream_name)726 int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */)
727 {
728 	int fd = -1;
729 	wan_ioctl_reset_tether_stats stats;
730 
731 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
732         IPACMERR("Failed opening %s.\n", DEVICE_NAME);
733         return FAIL_HARDWARE;
734     }
735 
736     memset(stats.upstreamIface, 0, IFNAMSIZ);
737     if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
738 		IPACMERR("String truncation occurred on upstream\n");
739 		close(fd);
740 		return FAIL_INPUT_CHECK;
741 	}
742 	stats.reset_stats = true;
743 	if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) {
744 		IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
745 		close(fd);
746 		return FAIL_HARDWARE;
747 	}
748 	IPACMDBG_H("Reset Interface %s stats\n", upstream_name);
749 	close(fd);
750 	return IPACM_SUCCESS;
751 }
752 
GetInstance()753 IPACM_OffloadManager* IPACM_OffloadManager::GetInstance()
754 {
755 	if(pInstance == NULL)
756 		pInstance = new IPACM_OffloadManager();
757 
758 	return pInstance;
759 }
760 
search_framwork_cache(char * interface_name)761 bool IPACM_OffloadManager::search_framwork_cache(char * interface_name)
762 {
763 	bool rel = false;
764 
765 	/* IPACM needs to kee old FDs, can't clear */
766 	IPACMDBG_H("check netdev(%s)\n", interface_name);
767 
768 	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
769 	{
770 		if(event_cache[i].valid == true)
771 		{
772 			//do the compare
773 			if (strncmp(event_cache[i].dev_name,
774 					interface_name,
775 					sizeof(event_cache[i].dev_name)) == 0)
776 			{
777 				IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event);
778 				/* post event again */
779 				if (event_cache[i].event == IPA_DOWNSTREAM_ADD)
780 					addDownstream(interface_name, event_cache[i].prefix_cache);
781 				else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT)
782 					setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6);
783 				else
784 					IPACMERR("wrong event cached (%d)", event_cache[i].event);
785 				event_cache[i].valid = false;
786 				rel = true;
787 			}
788 		}
789 	}
790 	IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name);
791 	return rel;
792 }
793 
push_iface_up(const char * if_name,bool upstream)794 int IPACM_OffloadManager::push_iface_up(const char * if_name, bool upstream)
795 {
796 	ipacm_cmd_q_data evt_data;
797 	ipacm_event_data_fid *data_fid = NULL;
798 	ipacm_event_data_mac *data = NULL;
799 	int index;
800 
801 	IPACMDBG_H("name %s, upstream %d\n",
802 							 if_name, upstream);
803 
804 	if(ipa_get_if_index(if_name, &index))
805 	{
806 		IPACMERR("netdev(%s) not registered ignored\n", if_name);
807 		return SUCCESS;
808 	}
809 
810 	if(strncmp(if_name, "rmnet_data", 10) == 0 && upstream)
811 	{
812 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
813 		if(data_fid == NULL)
814 		{
815 			IPACMERR("unable to allocate memory for event data_fid\n");
816 			return FAIL_HARDWARE;
817 		}
818 		data_fid->if_index = index;
819 		evt_data.event = IPA_LINK_UP_EVENT;
820 		evt_data.evt_data = data_fid;
821 		IPACMDBG_H("Posting IPA_LINK_UP_EVENT with if index: %d\n",
822 							 data_fid->if_index);
823 		IPACM_EvtDispatcher::PostEvt(&evt_data);
824 	}
825 
826 	if(strncmp(if_name, "rndis", 5) == 0 && !upstream)
827 	{
828 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
829 		if(data_fid == NULL)
830 		{
831 			IPACMERR("unable to allocate memory for event data_fid\n");
832 			return FAIL_HARDWARE;
833 		}
834 		data_fid->if_index = index;
835         evt_data.event = IPA_USB_LINK_UP_EVENT;
836 		evt_data.evt_data = data_fid;
837 		IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
838 				data_fid->if_index);
839 		IPACM_EvtDispatcher::PostEvt(&evt_data);
840 	}
841 
842 	if((strncmp(if_name, "softap", 6) == 0 || strncmp(if_name, "wlan", 4) == 0 ) && !upstream)
843 	{
844 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
845 		if(data_fid == NULL)
846 		{
847 			IPACMERR("unable to allocate memory for event data_fid\n");
848 			return FAIL_HARDWARE;
849 		}
850 		data_fid->if_index = index;
851 		evt_data.event = IPA_WLAN_AP_LINK_UP_EVENT;
852 		evt_data.evt_data = data_fid;
853 		IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
854 			data_fid->if_index);
855 		IPACM_EvtDispatcher::PostEvt(&evt_data);
856 	}
857 
858 	if(strncmp(if_name, "wlan", 4) == 0 && upstream)
859 	{
860 		data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
861 		if(data == NULL)
862 		{
863 			IPACMERR("unable to allocate memory for event_wlan data\n");
864 			return FAIL_HARDWARE;
865 		}
866 		data->if_index = index;
867 		evt_data.event = IPA_WLAN_STA_LINK_UP_EVENT;
868 		evt_data.evt_data = data;
869 		IPACMDBG_H("Posting IPA_WLAN_STA_LINK_UP_EVENT with if index: %d\n",
870 			data->if_index);
871 		IPACM_EvtDispatcher::PostEvt(&evt_data);
872 	}
873 
874 	return IPACM_SUCCESS;
875 }
876 
push_framework_event(const char * if_name,_ipacm_offload_prefix prefix)877 bool IPACM_OffloadManager::push_framework_event(const char * if_name, _ipacm_offload_prefix prefix)
878 {
879 	bool ret =  false;
880 
881 	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
882 	{
883 		if(event_cache[latest_cache_index].valid == false)
884 		{
885 			//do the copy
886 			event_cache[latest_cache_index].valid = true;
887 			event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
888 			memcpy(event_cache[latest_cache_index].dev_name, if_name,
889 				sizeof(event_cache[latest_cache_index].dev_name));
890 			memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix,
891 				sizeof(event_cache[latest_cache_index].prefix_cache));
892 
893 			if (prefix.iptype == IPA_IP_v4) {
894 				IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
895 						event_cache[latest_cache_index].event,
896 						event_cache[latest_cache_index].prefix_cache.v4Addr,
897 						event_cache[latest_cache_index].prefix_cache.v4Mask,
898 						event_cache[latest_cache_index].dev_name,
899 						latest_cache_index);
900 			} else {
901 				IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
902 						event_cache[latest_cache_index].event,
903 						event_cache[latest_cache_index].prefix_cache.v6Addr[0],
904 						event_cache[latest_cache_index].prefix_cache.v6Addr[1],
905 						event_cache[latest_cache_index].prefix_cache.v6Addr[2],
906 						event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
907 				IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d),\n",
908 						event_cache[latest_cache_index].prefix_cache.v6Mask[0],
909 						event_cache[latest_cache_index].prefix_cache.v6Mask[1],
910 						event_cache[latest_cache_index].prefix_cache.v6Mask[2],
911 						event_cache[latest_cache_index].prefix_cache.v6Mask[3],
912 						event_cache[latest_cache_index].dev_name,
913 						latest_cache_index);
914 			}
915 			latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
916 			ret = true;
917 			break;
918 		}
919 		latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
920 		if(i == MAX_EVENT_CACHE - 1)
921 		{
922 			IPACMDBG_H(" run out of event cache (%d)\n", i);
923 			ret = false;
924 		}
925 	}
926 	return ret;
927 }
928