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 return ; 63 } 64 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 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 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 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 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 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 181 bool IPACM_OffloadManager::isStaApSupported() 182 { 183 return true; 184 } 185 186 187 RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */) 188 { 189 return SUCCESS; 190 } 191 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 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 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 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 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 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 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 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 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 683 IPACM_OffloadManager* IPACM_OffloadManager::GetInstance() 684 { 685 if(pInstance == NULL) 686 pInstance = new IPACM_OffloadManager(); 687 688 return pInstance; 689 } 690 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