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