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, "a);
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