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