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