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