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 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 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 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 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 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 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 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 183 bool IPACM_OffloadManager::isStaApSupported() 184 { 185 return true; 186 } 187 188 189 RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */) 190 { 191 return SUCCESS; 192 } 193 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 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 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 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 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 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 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 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 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 693 IPACM_OffloadManager* IPACM_OffloadManager::GetInstance() 694 { 695 if(pInstance == NULL) 696 pInstance = new IPACM_OffloadManager(); 697 698 return pInstance; 699 } 700 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