1 /*
2 Copyright (c) 2017-2019, 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 int IPACM_OffloadManager::num_offload_v4_tethered_iface = 0;
55 
IPACM_OffloadManager()56 IPACM_OffloadManager::IPACM_OffloadManager()
57 {
58 	default_gw_index = INVALID_IFACE;
59 	upstream_v4_up = false;
60 	upstream_v6_up = false;
61 	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
62 	latest_cache_index = 0;
63 	elrInstance = NULL;
64 	touInstance = NULL;
65 	return ;
66 }
67 
registerEventListener(IpaEventListener * eventlistener)68 RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener)
69 {
70 	RET result = SUCCESS;
71 	if (elrInstance == NULL) {
72 		IPACMDBG_H("get registerEventListener \n");
73 		elrInstance = eventlistener;
74 	} else {
75 		IPACMDBG_H("already have EventListener previously, override \n");
76 		elrInstance = eventlistener;
77 		result = FAIL_INPUT_CHECK;
78 	}
79 	return SUCCESS;
80 }
81 
unregisterEventListener(IpaEventListener *)82 RET IPACM_OffloadManager::unregisterEventListener(IpaEventListener* )
83 {
84 	RET result = SUCCESS;
85 	if (elrInstance)
86 		elrInstance = NULL;
87 	else {
88 		IPACMDBG_H("already unregisterEventListener previously \n");
89 		result = SUCCESS_DUPLICATE_CONFIG;
90 	}
91 	return SUCCESS;
92 }
93 
registerCtTimeoutUpdater(ConntrackTimeoutUpdater * timeoutupdater)94 RET IPACM_OffloadManager::registerCtTimeoutUpdater(ConntrackTimeoutUpdater* timeoutupdater)
95 {
96 	RET result = SUCCESS;
97 	if (touInstance == NULL)
98 	{
99 		IPACMDBG_H("get ConntrackTimeoutUpdater \n");
100 		touInstance = timeoutupdater;
101 	} else {
102 		IPACMDBG_H("already have ConntrackTimeoutUpdater previously, override \n");
103 		touInstance = timeoutupdater;
104 		result = FAIL_INPUT_CHECK;
105 	}
106 	return SUCCESS;
107 }
108 
unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater *)109 RET IPACM_OffloadManager::unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* )
110 {
111 	RET result = SUCCESS;
112 	if (touInstance)
113 		touInstance = NULL;
114 	else {
115 		IPACMDBG_H("already unregisterCtTimeoutUpdater previously \n");
116 		result = SUCCESS_DUPLICATE_CONFIG;
117 	}
118 	return SUCCESS;
119 }
120 
provideFd(int fd,unsigned int groups)121 RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups)
122 {
123 	struct timeval tv;
124 	IPACM_ConntrackClient *cc;
125 	int on = 1, rel = 0;
126 	struct sockaddr_nl	local;
127 	unsigned int addr_len;
128 
129 	cc = IPACM_ConntrackClient::GetInstance();
130 
131 	if(!cc)
132 	{
133 		IPACMERR("Init failed: cc %p\n", cc);
134 		return FAIL_HARDWARE;
135 	}
136 
137 	/* check socket name */
138 	memset(&local, 0, sizeof(struct sockaddr_nl));
139 	addr_len = sizeof(local);
140 	getsockname(fd, (struct sockaddr *)&local, (socklen_t *)&addr_len);
141 	IPACMDBG_H(" FD %d, nl_pad %d nl_pid %u\n", fd, local.nl_pad, local.nl_pid);
142 
143 	/* add the check if getting FDs already or not */
144 	if(cc->fd_tcp > -1 && cc->fd_udp > -1) {
145 		IPACMDBG_H("has valid FDs fd_tcp %d, fd_udp %d, ignore fd %d.\n", cc->fd_tcp, cc->fd_udp, fd);
146 		return SUCCESS;
147 	}
148 
149 	if (groups == cc->subscrips_tcp) {
150 		cc->fd_tcp = dup(fd);
151 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
152 		/* set netlink buf */
153 		rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
154 		if (rel == -1)
155 		{
156 			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
157 		}
158 	} else if (groups == cc->subscrips_udp) {
159 		/* Set receive timeout to 1s on the FD which is used to read conntrack dump. */
160 		memset(&tv,0, sizeof(struct timeval));
161 		tv.tv_sec = 1; /* 1s timeout */
162 		rel = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
163 		if (rel == -1)
164 		{
165 			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
166 		}
167 
168 		/* In Android we get conntrack handles once after tethering is enabled but we
169 		   loose connections info for embedded traffic if running before. So no NAT
170 		   entries are added for embedded traffic due to which we see NAT exception and
171 		   data takes S/W path which results in less throughput. Hence for embedded
172 		   traffic info, framework sends conntrack dump before providing handles. Here
173 		   reading ct entries before creating filter on Fd in order to have NAT entries
174 		   for both TCP/UDP embedded traffic.
175 		*/
176 		CtList->readConntrack(fd);
177 		/* Reset receive timeout on the FD which is used to read conntrack dump. */
178 		memset(&tv,0, sizeof(struct timeval));
179 		rel = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
180 		if (rel == -1)
181 		{
182 			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
183 		}
184 
185 		cc->fd_udp = dup(fd);
186 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
187 		/* set netlink buf */
188 		rel = setsockopt(cc->fd_udp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
189 		if (rel == -1)
190 		{
191 			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
192 		}
193 	} else {
194 		IPACMERR("Received unexpected fd with groups %d.\n", groups);
195 	}
196 	if(cc->fd_tcp >0 && cc->fd_udp >0) {
197 		IPACMDBG_H(" Got both fds from framework, start conntrack listener thread.\n");
198 		CtList->CreateConnTrackThreads();
199 	}
200 	return SUCCESS;
201 }
202 
clearAllFds()203 RET IPACM_OffloadManager::clearAllFds()
204 {
205 
206 	/* IPACM needs to kee old FDs, can't clear */
207 	IPACMDBG_H("Still use old Fds, can't clear \n");
208 	return SUCCESS;
209 }
210 
isStaApSupported()211 bool IPACM_OffloadManager::isStaApSupported()
212 {
213 	return true;
214 }
215 
216 
setLocalPrefixes(std::vector<Prefix> &)217 RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */)
218 {
219 	return SUCCESS;
220 }
221 
addDownstream(const char * downstream_name,const Prefix & prefix)222 RET IPACM_OffloadManager::addDownstream(const char * downstream_name, const Prefix &prefix)
223 {
224 	int index;
225 	ipacm_cmd_q_data evt;
226 	ipacm_event_ipahal_stream *evt_data;
227 	bool cache_need = false;
228 
229 	IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
230 
231 	if (prefix.fam == V4) {
232 		IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask);
233 	} else {
234 		IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n",
235 							prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]);
236 		IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n",
237 							prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]);
238 	}
239 
240 	/* check if netdev valid on device */
241 	if(ipa_get_if_index(downstream_name, &index))
242 	{
243 		IPACMERR("fail to get iface index.\n");
244 		return FAIL_INPUT_CHECK;
245 	}
246 
247 	/* Iface is valid, add to list if not present */
248 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
249 	{
250 		/* Iface is new, add it to the list */
251 		valid_ifaces.push_back(downstream_name);
252 		IPACMDBG_H("add iface(%s) to list\n", downstream_name);
253 	}
254 
255 	/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
256 	if (prefix.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v4))
257 		cache_need = true;
258 	if (prefix.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v6))
259 		cache_need = true;
260 
261 	if (cache_need)
262 	{
263 		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
264 
265 		/* copy to the cache */
266 		for(int i = 0; i < MAX_EVENT_CACHE ;i++)
267 		{
268 			if (latest_cache_index >= 0)
269 			{
270 				if(event_cache[latest_cache_index].valid == false)
271 				{
272 					//do the copy
273 					event_cache[latest_cache_index].valid = true;
274 					event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
275 					memcpy(event_cache[latest_cache_index].dev_name, downstream_name,
276 						sizeof(event_cache[latest_cache_index].dev_name));
277 					memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix,
278 						sizeof(event_cache[latest_cache_index].prefix_cache));
279 					if (prefix.fam == V4) {
280 						IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
281 							event_cache[latest_cache_index].event,
282 							event_cache[latest_cache_index].prefix_cache.v4Addr,
283 							event_cache[latest_cache_index].prefix_cache.v4Mask,
284 							event_cache[latest_cache_index].dev_name,
285 							latest_cache_index);
286 					} else {
287 						IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
288 							event_cache[latest_cache_index].event,
289 							event_cache[latest_cache_index].prefix_cache.v6Addr[0],
290 							event_cache[latest_cache_index].prefix_cache.v6Addr[1],
291 							event_cache[latest_cache_index].prefix_cache.v6Addr[2],
292 							event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
293 						IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n",
294 							event_cache[latest_cache_index].prefix_cache.v6Mask[0],
295 							event_cache[latest_cache_index].prefix_cache.v6Mask[1],
296 							event_cache[latest_cache_index].prefix_cache.v6Mask[2],
297 							event_cache[latest_cache_index].prefix_cache.v6Mask[3],
298 							event_cache[latest_cache_index].dev_name,
299 							latest_cache_index);
300 					}
301 					latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
302 					break;
303 				}
304 				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
305 			}
306 			if(i == MAX_EVENT_CACHE - 1)
307 			{
308 				IPACMDBG_H(" run out of event cache (%d)\n", i);
309 				return FAIL_HARDWARE;
310 			}
311 		}
312 
313 		return SUCCESS;
314 	}
315 
316 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
317 	if(evt_data == NULL)
318 	{
319 		IPACMERR("Failed to allocate memory.\n");
320 		return FAIL_HARDWARE;
321 	}
322 	memset(evt_data, 0, sizeof(*evt_data));
323 
324 	evt_data->if_index = index;
325 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
326 
327 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
328 	evt.evt_data = (void*)evt_data;
329 	evt.event = IPA_DOWNSTREAM_ADD;
330 
331 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n");
332 	IPACM_EvtDispatcher::PostEvt(&evt);
333 
334 	return SUCCESS;
335 }
336 
removeDownstream(const char * downstream_name,const Prefix & prefix)337 RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix)
338 {
339 	int index;
340 	ipacm_cmd_q_data evt;
341 	ipacm_event_ipahal_stream *evt_data;
342 
343 	IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
344 	if(strnlen(downstream_name, sizeof(downstream_name)) == 0)
345 	{
346 		IPACMERR("iface length is 0.\n");
347 		return FAIL_HARDWARE;
348 	}
349 	if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
350 	{
351 		IPACMERR("iface is not present in list.\n");
352 		return FAIL_HARDWARE;
353 	}
354 
355 	if(ipa_get_if_index(downstream_name, &index))
356 	{
357 		IPACMERR("netdev(%s) already removed, ignored\n", downstream_name);
358 		return SUCCESS;
359 	}
360 
361 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
362 	if(evt_data == NULL)
363 	{
364 		IPACMERR("Failed to allocate memory.\n");
365 		return FAIL_HARDWARE;
366 	}
367 	memset(evt_data, 0, sizeof(*evt_data));
368 
369 	evt_data->if_index = index;
370 	memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
371 
372 	memset(&evt, 0, sizeof(ipacm_cmd_q_data));
373 	evt.evt_data = (void*)evt_data;
374 	evt.event = IPA_DOWNSTREAM_DEL;
375 
376 	IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n");
377 	IPACM_EvtDispatcher::PostEvt(&evt);
378 
379 	return SUCCESS;
380 }
381 
setUpstream(const char * upstream_name,const Prefix & gw_addr_v4,const Prefix & gw_addr_v6)382 RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6)
383 {
384 	int index;
385 	RET result = SUCCESS;
386 	bool cache_need = false;
387 
388 	/* if interface name is NULL, default route is removed */
389 	if(upstream_name != NULL)
390 	{
391 		IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam);
392 	}
393 	else
394 	{
395 		IPACMDBG_H("setUpstream clean upstream_name for ipv4-fam(%d) ipv6-fam(%d)\n", gw_addr_v4.fam, gw_addr_v6.fam);
396 	}
397 	if(upstream_name == NULL)
398 	{
399 		if (default_gw_index == INVALID_IFACE) {
400 			result = FAIL_INPUT_CHECK;
401 			for (index = 0; index < MAX_EVENT_CACHE; index++) {
402 				if (event_cache[index].valid == true &&
403 					event_cache[index ].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) {
404 					event_cache[index].valid = false;
405 					result = SUCCESS;
406 				}
407 			}
408 			IPACMERR("no previous upstream set before\n");
409 			return result;
410 		}
411 		if (gw_addr_v4.fam == V4 && upstream_v4_up == true) {
412 			IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
413 			post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
414 			upstream_v4_up = false;
415 		}
416 		if (gw_addr_v6.fam == V6 && upstream_v6_up == true) {
417 			IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
418 			post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
419 			upstream_v6_up = false;
420 		}
421 		default_gw_index = INVALID_IFACE;
422 	}
423 	else
424 	{
425 		/* check if netdev valid on device */
426 		if(ipa_get_if_index(upstream_name, &index))
427 		{
428 			IPACMERR("fail to get iface index.\n");
429 			return FAIL_INPUT_CHECK;
430 		}
431 
432 		/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
433 		if (gw_addr_v4.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v4))
434 			cache_need = true;
435 		if (gw_addr_v6.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v6))
436 			cache_need = true;
437 
438 		if (cache_need)
439 		{
440 			IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
441 #ifdef FEATURE_IPACM_RESTART
442 			/* add ipacm restart support */
443 			push_iface_up(upstream_name, true);
444 #endif
445 			/* copy to the cache */
446 			for(int i = 0; i < MAX_EVENT_CACHE ;i++)
447 			{
448 				if (latest_cache_index >= 0)
449 				{
450 					if(event_cache[latest_cache_index].valid == false)
451 					{
452 						//do the copy
453 						event_cache[latest_cache_index].valid = true;
454 						event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
455 						memcpy(event_cache[latest_cache_index].dev_name, upstream_name,
456 							sizeof(event_cache[latest_cache_index].dev_name));
457 						memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4,
458 							sizeof(event_cache[latest_cache_index].prefix_cache));
459 						memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6,
460 							sizeof(event_cache[latest_cache_index].prefix_cache_v6));
461 						if (gw_addr_v4.fam == V4) {
462 							IPACMDBG_H("cache event(%d) ipv4 gateway: (%x) dev(%s) on entry (%d)\n",
463 								event_cache[latest_cache_index].event,
464 								event_cache[latest_cache_index].prefix_cache.v4Addr,
465 								event_cache[latest_cache_index].dev_name,
466 								latest_cache_index);
467 						}
468 
469 						if (gw_addr_v6.fam == V6)
470 						{
471 							IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n",
472 								event_cache[latest_cache_index].event,
473 								event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0],
474 								event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1],
475 								event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2],
476 								event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3],
477 								event_cache[latest_cache_index].dev_name,
478 								latest_cache_index);
479 						}
480 						latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
481 						break;
482 					}
483 					latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
484 				}
485 				if(i == MAX_EVENT_CACHE - 1)
486 				{
487 					IPACMDBG_H(" run out of event cache (%d) \n", i);
488 					return FAIL_HARDWARE;
489 				}
490 			}
491 			return SUCCESS;
492 		}
493 
494 		/* reset the stats when switch from LTE->STA */
495 		if (index != default_gw_index) {
496 			IPACMDBG_H(" interface switched to %s\n", upstream_name);
497 			if (upstream_v4_up == true) {
498 				IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
499 				post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
500 				upstream_v4_up = false;
501 			}
502 			if (upstream_v6_up == true) {
503 				IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
504 				post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
505 				upstream_v6_up = false;
506 			}
507 			default_gw_index = INVALID_IFACE;
508 			if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0)
509 			{
510 				IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n");
511 				resetTetherStats(upstream_name);
512 			}
513 		}
514 
515 		if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) {
516 
517 			if (upstream_v4_up == false) {
518 				IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr);
519 				/* posting route add event for both IPv4 and IPv6 */
520 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
521 				upstream_v4_up = true;
522 			} else {
523 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
524 			}
525 
526 			if (upstream_v6_up == false) {
527 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
528 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
529 				/* check v6-address valid or not */
530 				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))
531 				{
532 					IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
533 				} else {
534 					post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
535 					upstream_v6_up = true;
536 				}
537 			} else {
538 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
539 			}
540 		} else if (gw_addr_v4.fam == V4 ) {
541 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
542 			if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) {
543 				/* clean up previous V6 upstream event */
544 				IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index);
545 				post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
546 				upstream_v6_up = false;
547 			}
548 
549 			if (upstream_v4_up == false) {
550 				IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr);
551 				/* posting route add event for both IPv4 and IPv6 */
552 				post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
553 				upstream_v4_up = true;
554 			} else {
555 				IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
556 				result = SUCCESS_DUPLICATE_CONFIG;
557 			}
558 		} else if (gw_addr_v6.fam == V6) {
559 			IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
560 			if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) {
561 				/* clean up previous V4 upstream event */
562 				IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index);
563 				post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
564 				upstream_v4_up = false;
565 			}
566 
567 			if (upstream_v6_up == false) {
568 				IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
569 						gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
570 				/* check v6-address valid or not */
571 				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))
572 				{
573 					IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
574 				} else {
575 					post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
576 					upstream_v6_up = true;
577 				}
578 			} else {
579 				IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
580 				result = SUCCESS_DUPLICATE_CONFIG;
581 			}
582 		}
583 		default_gw_index = index;
584 		IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name);
585 	}
586 	return result;
587 }
588 
stopAllOffload()589 RET IPACM_OffloadManager::stopAllOffload()
590 {
591 	Prefix v4gw, v6gw;
592 	RET result = SUCCESS;
593 
594 	memset(&v4gw, 0, sizeof(v4gw));
595 	memset(&v6gw, 0, sizeof(v6gw));
596 	v4gw.fam = V4;
597 	v6gw.fam = V6;
598 	IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam);
599 	result = setUpstream(NULL, v4gw, v6gw);
600 
601 	/* reset the event cache */
602 	default_gw_index = INVALID_IFACE;
603 	upstream_v4_up = false;
604 	upstream_v6_up = false;
605 	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
606 	latest_cache_index = 0;
607 	valid_ifaces.clear();
608 	IPACM_OffloadManager::num_offload_v4_tethered_iface = 0;
609 	return result;
610 }
611 
setQuota(const char * upstream_name,uint64_t mb)612 RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */)
613 {
614 	wan_ioctl_set_data_quota quota;
615 	int fd = -1, rc = 0, err_type = 0;
616 
617 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0)
618 	{
619 		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
620 		return FAIL_HARDWARE;
621 	}
622 
623 	quota.quota_mbytes = mb;
624 	quota.set_quota = true;
625 
626     memset(quota.interface_name, 0, IFNAMSIZ);
627     if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
628 		IPACMERR("String truncation occurred on upstream");
629 		close(fd);
630 		return FAIL_INPUT_CHECK;
631 	}
632 
633 	IPACMDBG_H("SET_DATA_QUOTA %s %llu\n", quota.interface_name, (long long)mb);
634 
635 	rc = ioctl(fd, WAN_IOC_SET_DATA_QUOTA, &quota);
636 
637 	if(rc != 0)
638 	{
639 		err_type = errno;
640 		close(fd);
641 		IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s err_type: %d\n", strerror(err_type), err_type);
642 		if (err_type == ENODEV) {
643 			IPACMDBG_H("Invalid argument.\n");
644 			return FAIL_UNSUPPORTED;
645 		}
646 		else {
647 			return FAIL_TRY_AGAIN;
648 		}
649 	}
650 	close(fd);
651 	return SUCCESS;
652 }
653 
getStats(const char * upstream_name,bool reset,OffloadStatistics & offload_stats)654 RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */,
655 		bool reset /* reset */, OffloadStatistics& offload_stats/* ret */)
656 {
657 	int fd = -1;
658 	wan_ioctl_query_tether_stats_all 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, 0, sizeof(stats));
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 = reset;
672 	stats.ipa_client = IPACM_CLIENT_MAX;
673 
674 	if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) {
675         IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno));
676 		close(fd);
677 		return FAIL_TRY_AGAIN;
678 	}
679 	/* feedback to IPAHAL*/
680 	offload_stats.tx = stats.tx_bytes;
681 	offload_stats.rx = stats.rx_bytes;
682 
683 	IPACMDBG_H("send getStats tx:%llu rx:%llu \n", (long long)offload_stats.tx, (long long)offload_stats.rx);
684 	close(fd);
685 	return SUCCESS;
686 }
687 
post_route_evt(enum ipa_ip_type iptype,int index,ipa_cm_event_id event,const Prefix & gw_addr)688 int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr)
689 {
690 	ipacm_cmd_q_data evt;
691 	ipacm_event_data_iptype *evt_data_route;
692 
693 	evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype));
694 	if(evt_data_route == NULL)
695 	{
696 		IPACMERR("Failed to allocate memory.\n");
697 		return -EFAULT;
698 	}
699 	memset(evt_data_route, 0, sizeof(*evt_data_route));
700 
701 	evt_data_route->if_index = index;
702 	evt_data_route->if_index_tether = 0;
703 	evt_data_route->iptype = iptype;
704 
705 	IPACMDBG_H("gw_addr.v4Addr: %d, gw_addr.v6Addr: %08x:%08x:%08x:%08x \n",
706 			gw_addr.v4Addr,gw_addr.v6Addr[0],gw_addr.v6Addr[1],gw_addr.v6Addr[2],gw_addr.v6Addr[3]);
707 
708 #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
709 	evt_data_route->ipv4_addr_gw = gw_addr.v4Addr;
710 	evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0];
711 	evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1];
712 	evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2];
713 	evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3];
714 	IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw);
715 	IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
716 					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]);
717 #endif
718 	if (event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) {
719 		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
720 			evt_data_route->if_index_tether, evt_data_route->iptype);
721 	}
722 	else if (event == IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT) {
723 		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) tether_fid(%d) ip-type(%d)\n",
724 				evt_data_route->if_index,
725 				evt_data_route->if_index_tether, evt_data_route->iptype);
726 	}
727 	memset(&evt, 0, sizeof(evt));
728 	evt.evt_data = (void*)evt_data_route;
729 	evt.event = event;
730 
731 	IPACM_EvtDispatcher::PostEvt(&evt);
732 
733 	return 0;
734 }
735 
ipa_get_if_index(const char * if_name,int * if_index)736 int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index)
737 {
738 	int fd;
739 	struct ifreq ifr;
740 
741 	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
742 	{
743 		IPACMERR("get interface index socket create failed \n");
744 		return IPACM_FAILURE;
745 	}
746 
747 	if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) {
748 		IPACMERR("interface name overflows: len %zu\n", strnlen(if_name, sizeof(if_name)));
749 		close(fd);
750 		return IPACM_FAILURE;
751 	}
752 
753 	memset(&ifr, 0, sizeof(struct ifreq));
754 	(void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
755 	IPACMDBG_H("interface name (%s)\n", if_name);
756 
757 	if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
758 	{
759 		IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
760 		close(fd);
761 		return IPACM_FAILURE;
762 	}
763 
764 	*if_index = ifr.ifr_ifindex;
765 	IPACMDBG_H("Interface netdev index %d\n", *if_index);
766 	close(fd);
767 	return IPACM_SUCCESS;
768 }
769 
resetTetherStats(const char * upstream_name)770 int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */)
771 {
772 	int fd = -1;
773 	wan_ioctl_reset_tether_stats stats;
774 
775 	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
776         IPACMERR("Failed opening %s.\n", DEVICE_NAME);
777         return FAIL_HARDWARE;
778     }
779 
780     memset(stats.upstreamIface, 0, IFNAMSIZ);
781     if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
782 		IPACMERR("String truncation occurred on upstream\n");
783 		close(fd);
784 		return FAIL_INPUT_CHECK;
785 	}
786 	stats.reset_stats = true;
787 	if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) {
788 		IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
789 		close(fd);
790 		return FAIL_HARDWARE;
791 	}
792 	IPACMDBG_H("Reset Interface %s stats\n", upstream_name);
793 	close(fd);
794 	return IPACM_SUCCESS;
795 }
796 
GetInstance()797 IPACM_OffloadManager* IPACM_OffloadManager::GetInstance()
798 {
799 	if(pInstance == NULL)
800 		pInstance = new IPACM_OffloadManager();
801 
802 	return pInstance;
803 }
804 
search_framwork_cache(char * interface_name)805 bool IPACM_OffloadManager::search_framwork_cache(char * interface_name)
806 {
807 	bool rel = false;
808 	bool cache_need = false;
809 
810 	/* IPACM needs to kee old FDs, can't clear */
811 	IPACMDBG_H("check netdev(%s)\n", interface_name);
812 
813 	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
814 	{
815 		cache_need = false;
816 		if(event_cache[i].valid == true)
817 		{
818 			//do the compare
819 			if (strncmp(event_cache[i].dev_name,
820 					interface_name,
821 					sizeof(event_cache[i].dev_name)) == 0)
822 			{
823 				IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event);
824 				/* post event again */
825 				if (event_cache[i].event == IPA_DOWNSTREAM_ADD) {
826 					/* check if downsteam netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
827 					if (event_cache[i].prefix_cache.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(event_cache[i].dev_name, IPA_IP_v4))
828 						cache_need = true;
829 					if (event_cache[i].prefix_cache.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(event_cache[i].dev_name, IPA_IP_v6))
830 						cache_need = true;
831 					if (cache_need) {
832 						IPACMDBG_H("still need cache (%d), index (%d) ip-family (%d)\n", cache_need, i, event_cache[i].prefix_cache.fam);
833 						break;
834 					} else {
835 						IPACMDBG_H("no need cache (%d), handling it event (%d)\n", cache_need, event_cache[i].event);
836 					addDownstream(interface_name, event_cache[i].prefix_cache);
837 					}
838 				} else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) {
839 					/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
840 					if (event_cache[i].prefix_cache.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(event_cache[i].dev_name, IPA_IP_v4))
841 						cache_need = true;
842 					if (event_cache[i].prefix_cache_v6.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(event_cache[i].dev_name, IPA_IP_v6))
843 						cache_need = true;
844 					if (cache_need) {
845 						IPACMDBG_H("still need cache (%d), index (%d)\n", cache_need, i);
846 						break;
847 					} else {
848 						IPACMDBG_H("no need cache (%d), handling it event (%d)\n", cache_need, event_cache[i].event);
849 					setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6);
850 					}
851 				} else {
852 						IPACMERR("wrong event cached (%d) index (%d)\n", event_cache[i].event, i);
853 				}
854 
855 				/* reset entry */
856 				event_cache[i].valid = false;
857 				rel = true;
858 				IPACMDBG_H("reset entry (%d)", i);
859 			}
860 		}
861 	}
862 	IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name);
863 	return rel;
864 }
865 
866 #ifdef FEATURE_IPACM_RESTART
push_iface_up(const char * if_name,bool upstream)867 int IPACM_OffloadManager::push_iface_up(const char * if_name, bool upstream)
868 {
869 	ipacm_cmd_q_data evt_data;
870 	ipacm_event_data_fid *data_fid = NULL;
871 	ipacm_event_data_mac *data = NULL;
872 	int index;
873 
874 	IPACMDBG_H("name %s, upstream %d\n",
875 							 if_name, upstream);
876 
877 	if(ipa_get_if_index(if_name, &index))
878 	{
879 		IPACMERR("netdev(%s) not registered ignored\n", if_name);
880 		return SUCCESS;
881 	}
882 
883 	if(strncmp(if_name, "rmnet_data", 10) == 0 && upstream)
884 	{
885 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
886 		if(data_fid == NULL)
887 		{
888 			IPACMERR("unable to allocate memory for event data_fid\n");
889 			return FAIL_HARDWARE;
890 		}
891 		data_fid->if_index = index;
892 		evt_data.event = IPA_LINK_UP_EVENT;
893 		evt_data.evt_data = data_fid;
894 		IPACMDBG_H("Posting IPA_LINK_UP_EVENT with if index: %d\n",
895 							 data_fid->if_index);
896 		IPACM_EvtDispatcher::PostEvt(&evt_data);
897 	}
898 
899 	if(strncmp(if_name, "rndis", 5) == 0 && !upstream)
900 	{
901 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
902 		if(data_fid == NULL)
903 		{
904 			IPACMERR("unable to allocate memory for event data_fid\n");
905 			return FAIL_HARDWARE;
906 		}
907 		data_fid->if_index = index;
908 		evt_data.event = IPA_USB_LINK_UP_EVENT;
909 		evt_data.evt_data = data_fid;
910 		IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
911 				data_fid->if_index);
912 		IPACM_EvtDispatcher::PostEvt(&evt_data);
913 	}
914 
915 	if((strncmp(if_name, "softap", 6) == 0 || strncmp(if_name, "wlan", 4) == 0 ) && !upstream)
916 	{
917 		data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
918 		if(data_fid == NULL)
919 		{
920 			IPACMERR("unable to allocate memory for event data_fid\n");
921 			return FAIL_HARDWARE;
922 		}
923 		data_fid->if_index = index;
924 		evt_data.event = IPA_WLAN_AP_LINK_UP_EVENT;
925 		evt_data.evt_data = data_fid;
926 		IPACMDBG_H("Posting IPA_WLAN_AP_LINK_UP_EVENT with if index: %d\n",
927 			data_fid->if_index);
928 		IPACM_EvtDispatcher::PostEvt(&evt_data);
929 	}
930 
931 	if(strncmp(if_name, "wlan", 4) == 0 && upstream)
932 	{
933 		data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
934 		if(data == NULL)
935 		{
936 			IPACMERR("unable to allocate memory for event_wlan data\n");
937 			return FAIL_HARDWARE;
938 		}
939 		data->if_index = index;
940 		evt_data.event = IPA_WLAN_STA_LINK_UP_EVENT;
941 		evt_data.evt_data = data;
942 		IPACMDBG_H("Posting IPA_WLAN_STA_LINK_UP_EVENT with if index: %d\n",
943 			data->if_index);
944 		IPACM_EvtDispatcher::PostEvt(&evt_data);
945 	}
946 
947 	return IPACM_SUCCESS;
948 }
949 #endif
950 
951 
push_framework_event(const char * if_name,_ipacm_offload_prefix prefix)952 bool IPACM_OffloadManager::push_framework_event(const char * if_name, _ipacm_offload_prefix prefix)
953 {
954 	bool ret =  false;
955 
956 	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
957 	{
958 		if((latest_cache_index >= 0) && (latest_cache_index < MAX_EVENT_CACHE) &&
959 			(event_cache[latest_cache_index].valid == false))
960 		{
961 			//do the copy
962 			event_cache[latest_cache_index].valid = true;
963 			event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
964 			memcpy(event_cache[latest_cache_index].dev_name, if_name,
965 				sizeof(event_cache[latest_cache_index].dev_name));
966 			memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix,
967 				sizeof(event_cache[latest_cache_index].prefix_cache));
968 
969 			if (prefix.iptype == IPA_IP_v4) {
970 				IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
971 						event_cache[latest_cache_index].event,
972 						event_cache[latest_cache_index].prefix_cache.v4Addr,
973 						event_cache[latest_cache_index].prefix_cache.v4Mask,
974 						event_cache[latest_cache_index].dev_name,
975 						latest_cache_index);
976 			} else {
977 				IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
978 						event_cache[latest_cache_index].event,
979 						event_cache[latest_cache_index].prefix_cache.v6Addr[0],
980 						event_cache[latest_cache_index].prefix_cache.v6Addr[1],
981 						event_cache[latest_cache_index].prefix_cache.v6Addr[2],
982 						event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
983 				IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d),\n",
984 						event_cache[latest_cache_index].prefix_cache.v6Mask[0],
985 						event_cache[latest_cache_index].prefix_cache.v6Mask[1],
986 						event_cache[latest_cache_index].prefix_cache.v6Mask[2],
987 						event_cache[latest_cache_index].prefix_cache.v6Mask[3],
988 						event_cache[latest_cache_index].dev_name,
989 						latest_cache_index);
990 			}
991 			latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
992 			ret = true;
993 			break;
994 		}
995 		latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
996 		if(i == MAX_EVENT_CACHE - 1)
997 		{
998 			IPACMDBG_H(" run out of event cache (%d)\n", i);
999 			ret = false;
1000 		}
1001 	}
1002 	return ret;
1003 }
1004