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.
28 */
29 #ifndef DBG
30 #define DBG true
31 #endif /* DBG */
32 #define LOG_TAG "IPAHALService"
33
34 /* HIDL Includes */
35 #include <hwbinder/IPCThreadState.h>
36 #include <hwbinder/ProcessState.h>
37
38 /* Kernel Includes */
39 #include <linux/netfilter/nfnetlink_compat.h>
40
41 /* External Includes */
42 #include <cutils/log.h>
43 #include <cstring>
44 #include <sys/socket.h>
45 #include <sys/types.h>
46 #include <vector>
47
48 /* Internal Includes */
49 #include "HAL.h"
50 #include "LocalLogBuffer.h"
51 #include "PrefixParser.h"
52
53 /* Namespace pollution avoidance */
54 using ::android::hardware::Void;
55 using ::android::status_t;
56
57 using RET = ::IOffloadManager::RET;
58 using Prefix = ::IOffloadManager::Prefix;
59
60 using ::std::map;
61 using ::std::vector;
62
63
64 /* ------------------------------ PUBLIC ------------------------------------ */
makeIPAHAL(int version,IOffloadManager * mgr)65 Return<::android::sp<HAL>> HAL::makeIPAHAL(int version, IOffloadManager* mgr) {
66 android::hardware::ProcessState::initWithMmapSize((size_t)(2 * KERNEL_PAGE));
67
68 if (DBG)
69 ALOGI("makeIPAHAL(%d, %s)", version,
70 (mgr != nullptr) ? "provided" : "null");
71 if (nullptr == mgr) return NULL;
72 else if (version != 1) return NULL;
73 ::android::sp<HAL> ret = new HAL(mgr);
74 if (nullptr == ret) return NULL;
75 configureRpcThreadpool(1, false);
76 ret->registerAsSystemService("ipacm");
77 return ret;
78 } /* makeIPAHAL */
79
80
81 /* ------------------------------ PRIVATE ----------------------------------- */
HAL(IOffloadManager * mgr)82 HAL::HAL(IOffloadManager* mgr) : mLogs("HAL Function Calls", 50) {
83 mIPA = mgr;
84 mCb.clear();
85 mCbIpa = nullptr;
86 mCbCt = nullptr;
87 } /* HAL */
88
registerAsSystemService(const char * name)89 void HAL::registerAsSystemService(const char* name) {
90 status_t ret = 0;
91
92 ret = IOffloadControl::registerAsService();
93 if (ret != 0) ALOGE("Failed to register IOffloadControl (%d) name(%s)", ret, name);
94 else if (DBG) {
95 ALOGI("Successfully registered IOffloadControl");
96 }
97
98 ret = IOffloadConfig::registerAsService();
99 if (ret != 0) ALOGE("Failed to register IOffloadConfig (%d)", ret);
100 else if (DBG) {
101 ALOGI("Successfully registered IOffloadConfig");
102 }
103 } /* registerAsSystemService */
104
doLogcatDump()105 void HAL::doLogcatDump() {
106 ALOGD("mHandles");
107 ALOGD("========");
108 /* @TODO This will segfault if they aren't initialized and I don't currently
109 * care to check for initialization in a function that isn't used anyways
110 * ALOGD("fd1->%d", mHandle1->data[0]);
111 * ALOGD("fd2->%d", mHandle2->data[0]);
112 */
113 ALOGD("========");
114 } /* doLogcatDump */
115
makeInputCheckFailure(string customErr)116 HAL::BoolResult HAL::makeInputCheckFailure(string customErr) {
117 BoolResult ret;
118 ret.success = false;
119 ret.errMsg = "Failed Input Checks: " + customErr;
120 return ret;
121 } /* makeInputCheckFailure */
122
ipaResultToBoolResult(RET in)123 HAL::BoolResult HAL::ipaResultToBoolResult(RET in) {
124 BoolResult ret;
125 ret.success = (in >= RET::SUCCESS);
126 switch (in) {
127 case RET::FAIL_TOO_MANY_PREFIXES:
128 ret.errMsg = "Too Many Prefixes Provided";
129 break;
130 case RET::FAIL_UNSUPPORTED:
131 ret.errMsg = "Unsupported by Hardware";
132 break;
133 case RET::FAIL_INPUT_CHECK:
134 ret.errMsg = "Failed Input Checks";
135 break;
136 case RET::FAIL_HARDWARE:
137 ret.errMsg = "Hardware did not accept";
138 break;
139 case RET::FAIL_TRY_AGAIN:
140 ret.errMsg = "Try Again";
141 break;
142 case RET::SUCCESS:
143 ret.errMsg = "Successful";
144 break;
145 case RET::SUCCESS_DUPLICATE_CONFIG:
146 ret.errMsg = "Successful: Was a duplicate configuration";
147 break;
148 case RET::SUCCESS_NO_OP:
149 ret.errMsg = "Successful: No action needed";
150 break;
151 case RET::SUCCESS_OPTIMIZED:
152 ret.errMsg = "Successful: Performed optimized version of action";
153 break;
154 default:
155 ret.errMsg = "Unknown Error";
156 break;
157 }
158 return ret;
159 } /* ipaResultToBoolResult */
160
161 /* This will likely always result in doubling the number of loops the execution
162 * goes through. Obviously that is suboptimal. But if we first translate
163 * away from all HIDL specific code, then we can avoid sprinkling HIDL
164 * dependencies everywhere.
165 */
convertHidlStrToStdStr(hidl_vec<hidl_string> in)166 vector<string> HAL::convertHidlStrToStdStr(hidl_vec<hidl_string> in) {
167 vector<string> ret;
168 for (size_t i = 0; i < in.size(); i++) {
169 string add = in[i];
170 ret.push_back(add);
171 }
172 return ret;
173 } /* convertHidlStrToStdStr */
174
registerEventListeners()175 void HAL::registerEventListeners() {
176 registerIpaCb();
177 registerCtCb();
178 } /* registerEventListeners */
179
registerIpaCb()180 void HAL::registerIpaCb() {
181 if (isInitialized() && mCbIpa == nullptr) {
182 LocalLogBuffer::FunctionLog fl("registerEventListener");
183 mCbIpa = new IpaEventRelay(mCb);
184 mIPA->registerEventListener(mCbIpa);
185 mLogs.addLog(fl);
186 } else {
187 ALOGE("Failed to registerIpaCb (isInitialized()=%s, (mCbIpa == nullptr)=%s)",
188 isInitialized() ? "true" : "false",
189 (mCbIpa == nullptr) ? "true" : "false");
190 }
191 } /* registerIpaCb */
192
registerCtCb()193 void HAL::registerCtCb() {
194 if (isInitialized() && mCbCt == nullptr) {
195 LocalLogBuffer::FunctionLog fl("registerCtTimeoutUpdater");
196 mCbCt = new CtUpdateAmbassador(mCb);
197 mIPA->registerCtTimeoutUpdater(mCbCt);
198 mLogs.addLog(fl);
199 } else {
200 ALOGE("Failed to registerCtCb (isInitialized()=%s, (mCbCt == nullptr)=%s)",
201 isInitialized() ? "true" : "false",
202 (mCbCt == nullptr) ? "true" : "false");
203 }
204 } /* registerCtCb */
205
unregisterEventListeners()206 void HAL::unregisterEventListeners() {
207 unregisterIpaCb();
208 unregisterCtCb();
209 } /* unregisterEventListeners */
210
unregisterIpaCb()211 void HAL::unregisterIpaCb() {
212 if (mCbIpa != nullptr) {
213 LocalLogBuffer::FunctionLog fl("unregisterEventListener");
214 mIPA->unregisterEventListener(mCbIpa);
215 mCbIpa = nullptr;
216 mLogs.addLog(fl);
217 } else {
218 ALOGE("Failed to unregisterIpaCb");
219 }
220 } /* unregisterIpaCb */
221
unregisterCtCb()222 void HAL::unregisterCtCb() {
223 if (mCbCt != nullptr) {
224 LocalLogBuffer::FunctionLog fl("unregisterCtTimeoutUpdater");
225 mIPA->unregisterCtTimeoutUpdater(mCbCt);
226 mCbCt = nullptr;
227 mLogs.addLog(fl);
228 } else {
229 ALOGE("Failed to unregisterCtCb");
230 }
231 } /* unregisterCtCb */
232
clearHandles()233 void HAL::clearHandles() {
234 ALOGI("clearHandles()");
235 /* @TODO handle this more gracefully... also remove the log
236 *
237 * Things that would be nice, but I can't do:
238 * [1] Destroy the object (it's on the stack)
239 * [2] Call freeHandle (it's private)
240 *
241 * Things I can do but are hacks:
242 * [1] Look at code and notice that setTo immediately calls freeHandle
243 */
244 mHandle1.setTo(nullptr, true);
245 mHandle2.setTo(nullptr, true);
246 } /* clearHandles */
247
isInitialized()248 bool HAL::isInitialized() {
249 return mCb.get() != nullptr;
250 } /* isInitialized */
251
252
253 /* -------------------------- IOffloadConfig -------------------------------- */
setHandles(const hidl_handle & fd1,const hidl_handle & fd2,setHandles_cb hidl_cb)254 Return<void> HAL::setHandles(
255 const hidl_handle &fd1,
256 const hidl_handle &fd2,
257 setHandles_cb hidl_cb
258 ) {
259 LocalLogBuffer::FunctionLog fl(__func__);
260
261 if (fd1->numFds != 1) {
262 BoolResult res = makeInputCheckFailure("Must provide exactly one FD per handle (fd1)");
263 hidl_cb(res.success, res.errMsg);
264 fl.setResult(res.success, res.errMsg);
265
266 mLogs.addLog(fl);
267 return Void();
268 }
269
270 if (fd2->numFds != 1) {
271 BoolResult res = makeInputCheckFailure("Must provide exactly one FD per handle (fd2)");
272 hidl_cb(res.success, res.errMsg);
273 fl.setResult(res.success, res.errMsg);
274
275 mLogs.addLog(fl);
276 return Void();
277 }
278
279 /* The = operator calls freeHandle internally. Therefore, if we were using
280 * these handles previously, they're now gone... forever. But hopefully the
281 * new ones kick in very quickly.
282 *
283 * After freeing anything previously held, it will dup the FD so we have our
284 * own copy.
285 */
286 mHandle1 = fd1;
287 mHandle2 = fd2;
288
289 /* Log the DUPed FD instead of the actual input FD so that we can lookup
290 * this value in ls -l /proc/<pid>/<fd>
291 */
292 fl.addArg("fd1", mHandle1->data[0]);
293 fl.addArg("fd2", mHandle2->data[0]);
294
295 /* Try to provide each handle to IPACM. Destroy our DUPed hidl_handles if
296 * IPACM does not like either input. This keeps us from leaking FDs or
297 * providing half solutions.
298 *
299 * @TODO unfortunately, this does not cover duplicate configs where IPACM
300 * thinks it is still holding on to a handle that we would have freed above.
301 * It also probably means that IPACM would not know about the first FD being
302 * freed if it rejects the second FD.
303 */
304 RET ipaReturn = mIPA->provideFd(mHandle1->data[0], UDP_SUBSCRIPTIONS);
305 if (ipaReturn == RET::SUCCESS) {
306 ipaReturn = mIPA->provideFd(mHandle2->data[0], TCP_SUBSCRIPTIONS);
307 }
308
309 if (ipaReturn != RET::SUCCESS) {
310 ALOGE("IPACM failed to accept the FDs (%d %d)", mHandle1->data[0],
311 mHandle2->data[0]);
312 clearHandles();
313 } else {
314 /* @TODO remove logs after stabilization */
315 ALOGI("IPACM was provided two FDs (%d, %d)", mHandle1->data[0],
316 mHandle2->data[0]);
317 }
318
319 BoolResult res = ipaResultToBoolResult(ipaReturn);
320 hidl_cb(res.success, res.errMsg);
321
322 fl.setResult(res.success, res.errMsg);
323 mLogs.addLog(fl);
324 return Void();
325 } /* setHandles */
326
327
328 /* -------------------------- IOffloadControl ------------------------------- */
initOffload(const::android::sp<ITetheringOffloadCallback> & cb,initOffload_cb hidl_cb)329 Return<void> HAL::initOffload
330 (
331 const ::android::sp<ITetheringOffloadCallback>& cb,
332 initOffload_cb hidl_cb
333 ) {
334 LocalLogBuffer::FunctionLog fl(__func__);
335
336 if (isInitialized()) {
337 BoolResult res = makeInputCheckFailure("Already initialized");
338 hidl_cb(res.success, res.errMsg);
339 fl.setResult(res.success, res.errMsg);
340 mLogs.addLog(fl);
341 } else {
342 /* Should storing the CB be a function? */
343 mCb = cb;
344 registerEventListeners();
345 BoolResult res = ipaResultToBoolResult(RET::SUCCESS);
346 hidl_cb(res.success, res.errMsg);
347 fl.setResult(res.success, res.errMsg);
348 mLogs.addLog(fl);
349 }
350
351 return Void();
352 } /* initOffload */
353
stopOffload(stopOffload_cb hidl_cb)354 Return<void> HAL::stopOffload
355 (
356 stopOffload_cb hidl_cb
357 ) {
358 LocalLogBuffer::FunctionLog fl(__func__);
359
360 if (!isInitialized()) {
361 BoolResult res = makeInputCheckFailure("Was never initialized");
362 hidl_cb(res.success, res.errMsg);
363 fl.setResult(res.success, res.errMsg);
364 mLogs.addLog(fl);
365 } else {
366 /* Should removing the CB be a function? */
367 mCb.clear();
368 unregisterEventListeners();
369
370 RET ipaReturn = mIPA->stopAllOffload();
371 if (ipaReturn != RET::SUCCESS) {
372 /* Ignore IPAs return value here and provide why stopAllOffload
373 * failed. However, if IPA failed to clearAllFds, then we can't
374 * clear our map because they may still be in use.
375 */
376 RET ret = mIPA->clearAllFds();
377 if (ret == RET::SUCCESS) {
378 clearHandles();
379 }
380 } else {
381 ipaReturn = mIPA->clearAllFds();
382 /* If IPA fails, they may still be using these for some reason. */
383 if (ipaReturn == RET::SUCCESS) {
384 clearHandles();
385 } else {
386 ALOGE("IPACM failed to return success for clearAllFds so they will not be released...");
387 }
388 }
389
390 BoolResult res = ipaResultToBoolResult(ipaReturn);
391 hidl_cb(res.success, res.errMsg);
392
393 fl.setResult(res.success, res.errMsg);
394 mLogs.addLog(fl);
395 }
396
397 return Void();
398 } /* stopOffload */
399
setLocalPrefixes(const hidl_vec<hidl_string> & prefixes,setLocalPrefixes_cb hidl_cb)400 Return<void> HAL::setLocalPrefixes
401 (
402 const hidl_vec<hidl_string>& prefixes,
403 setLocalPrefixes_cb hidl_cb
404 ) {
405 BoolResult res;
406 PrefixParser parser;
407 vector<string> prefixesStr = convertHidlStrToStdStr(prefixes);
408
409 LocalLogBuffer::FunctionLog fl(__func__);
410 fl.addArg("prefixes", prefixesStr);
411
412 memset(&res,0,sizeof(BoolResult));
413
414 if (!isInitialized()) {
415 BoolResult res = makeInputCheckFailure("Not initialized");
416 } else if(prefixesStr.size() < 1) {
417 res = ipaResultToBoolResult(RET::FAIL_INPUT_CHECK);
418 } else if (!parser.add(prefixesStr)) {
419 res = makeInputCheckFailure(parser.getLastErrAsStr());
420 } else {
421 res = ipaResultToBoolResult(RET::SUCCESS);
422 }
423
424 hidl_cb(res.success, res.errMsg);
425 fl.setResult(res.success, res.errMsg);
426 mLogs.addLog(fl);
427 return Void();
428 } /* setLocalPrefixes */
429
getForwardedStats(const hidl_string & upstream,getForwardedStats_cb hidl_cb)430 Return<void> HAL::getForwardedStats
431 (
432 const hidl_string& upstream,
433 getForwardedStats_cb hidl_cb
434 ) {
435 LocalLogBuffer::FunctionLog fl(__func__);
436 fl.addArg("upstream", upstream);
437
438 OffloadStatistics ret;
439 RET ipaReturn = mIPA->getStats(upstream.c_str(), true, ret);
440 if (ipaReturn == RET::SUCCESS) {
441 hidl_cb(ret.getTotalRxBytes(), ret.getTotalTxBytes());
442 fl.setResult(ret.getTotalRxBytes(), ret.getTotalTxBytes());
443 } else {
444 /* @TODO Ensure the output is zeroed, but this is probably not enough to
445 * tell Framework that an error has occurred. If, for example, they had
446 * not yet polled for statistics previously, they may incorrectly assume
447 * that simply no statistics have transpired on hardware path.
448 *
449 * Maybe ITetheringOffloadCallback:onEvent(OFFLOAD_STOPPED_ERROR) is
450 * enough to handle this case, time will tell.
451 */
452 hidl_cb(0, 0);
453 fl.setResult(0, 0);
454 }
455
456 mLogs.addLog(fl);
457 return Void();
458 } /* getForwardedStats */
459
setDataLimit(const hidl_string & upstream,uint64_t limit,setDataLimit_cb hidl_cb)460 Return<void> HAL::setDataLimit
461 (
462 const hidl_string& upstream,
463 uint64_t limit,
464 setDataLimit_cb hidl_cb
465 ) {
466 LocalLogBuffer::FunctionLog fl(__func__);
467 fl.addArg("upstream", upstream);
468 fl.addArg("limit", limit);
469
470 if (!isInitialized()) {
471 BoolResult res = makeInputCheckFailure("Not initialized (setDataLimit)");
472 hidl_cb(res.success, res.errMsg);
473 fl.setResult(res.success, res.errMsg);
474 } else {
475 RET ipaReturn = mIPA->setQuota(upstream.c_str(), limit);
476 if(ipaReturn == RET::FAIL_TRY_AGAIN) {
477 ipaReturn = RET::SUCCESS;
478 }
479 BoolResult res = ipaResultToBoolResult(ipaReturn);
480 hidl_cb(res.success, res.errMsg);
481 fl.setResult(res.success, res.errMsg);
482 }
483
484 mLogs.addLog(fl);
485 return Void();
486 } /* setDataLimit */
487
setUpstreamParameters(const hidl_string & iface,const hidl_string & v4Addr,const hidl_string & v4Gw,const hidl_vec<hidl_string> & v6Gws,setUpstreamParameters_cb hidl_cb)488 Return<void> HAL::setUpstreamParameters
489 (
490 const hidl_string& iface,
491 const hidl_string& v4Addr,
492 const hidl_string& v4Gw,
493 const hidl_vec<hidl_string>& v6Gws,
494 setUpstreamParameters_cb hidl_cb
495 ) {
496 vector<string> v6GwStrs = convertHidlStrToStdStr(v6Gws);
497
498 LocalLogBuffer::FunctionLog fl(__func__);
499 fl.addArg("iface", iface);
500 fl.addArg("v4Addr", v4Addr);
501 fl.addArg("v4Gw", v4Gw);
502 fl.addArg("v6Gws", v6GwStrs);
503
504 PrefixParser v4AddrParser;
505 PrefixParser v4GwParser;
506 PrefixParser v6GwParser;
507
508 /* @TODO maybe we should enforce that these addresses and gateways are fully
509 * qualified here. But then, how do we allow them to be empty/null as well
510 * while still preserving a sane API on PrefixParser?
511 */
512 if (!isInitialized()) {
513 BoolResult res = makeInputCheckFailure("Not initialized (setUpstreamParameters)");
514 hidl_cb(res.success, res.errMsg);
515 fl.setResult(res.success, res.errMsg);
516 } else if (!v4AddrParser.addV4(v4Addr) && !v4Addr.empty()) {
517 BoolResult res = makeInputCheckFailure(v4AddrParser.getLastErrAsStr());
518 hidl_cb(res.success, res.errMsg);
519 fl.setResult(res.success, res.errMsg);
520 } else if (!v4GwParser.addV4(v4Gw) && !v4Gw.empty()) {
521 BoolResult res = makeInputCheckFailure(v4GwParser.getLastErrAsStr());
522 hidl_cb(res.success, res.errMsg);
523 fl.setResult(res.success, res.errMsg);
524 } else if (v6GwStrs.size() >= 1 && !v6GwParser.addV6(v6GwStrs)) {
525 BoolResult res = makeInputCheckFailure(v6GwParser.getLastErrAsStr());
526 hidl_cb(res.success, res.errMsg);
527 fl.setResult(res.success, res.errMsg);
528 } else if (iface.size()>= 1) {
529 RET ipaReturn = mIPA->setUpstream(
530 iface.c_str(),
531 v4GwParser.getFirstPrefix(),
532 v6GwParser.getFirstPrefix());
533 BoolResult res = ipaResultToBoolResult(ipaReturn);
534 hidl_cb(res.success, res.errMsg);
535 fl.setResult(res.success, res.errMsg);
536 } else {
537 /* send NULL iface string when upstream down */
538 RET ipaReturn = mIPA->setUpstream(
539 NULL,
540 v4GwParser.getFirstPrefix(IP_FAM::V4),
541 v6GwParser.getFirstPrefix(IP_FAM::V6));
542 BoolResult res = ipaResultToBoolResult(ipaReturn);
543 hidl_cb(res.success, res.errMsg);
544 fl.setResult(res.success, res.errMsg);
545 }
546
547 mLogs.addLog(fl);
548 return Void();
549 } /* setUpstreamParameters */
550
addDownstream(const hidl_string & iface,const hidl_string & prefix,addDownstream_cb hidl_cb)551 Return<void> HAL::addDownstream
552 (
553 const hidl_string& iface,
554 const hidl_string& prefix,
555 addDownstream_cb hidl_cb
556 ) {
557 LocalLogBuffer::FunctionLog fl(__func__);
558 fl.addArg("iface", iface);
559 fl.addArg("prefix", prefix);
560
561 PrefixParser prefixParser;
562
563 if (!isInitialized()) {
564 BoolResult res = makeInputCheckFailure("Not initialized (setUpstreamParameters)");
565 hidl_cb(res.success, res.errMsg);
566 fl.setResult(res.success, res.errMsg);
567 }
568 else if (!prefixParser.add(prefix)) {
569 BoolResult res = makeInputCheckFailure(prefixParser.getLastErrAsStr());
570 hidl_cb(res.success, res.errMsg);
571 fl.setResult(res.success, res.errMsg);
572 } else {
573 RET ipaReturn = mIPA->addDownstream(
574 iface.c_str(),
575 prefixParser.getFirstPrefix());
576 BoolResult res = ipaResultToBoolResult(ipaReturn);
577 hidl_cb(res.success, res.errMsg);
578 fl.setResult(res.success, res.errMsg);
579 }
580
581 mLogs.addLog(fl);
582 return Void();
583 } /* addDownstream */
584
removeDownstream(const hidl_string & iface,const hidl_string & prefix,removeDownstream_cb hidl_cb)585 Return<void> HAL::removeDownstream
586 (
587 const hidl_string& iface,
588 const hidl_string& prefix,
589 removeDownstream_cb hidl_cb
590 ) {
591 LocalLogBuffer::FunctionLog fl(__func__);
592 fl.addArg("iface", iface);
593 fl.addArg("prefix", prefix);
594
595 PrefixParser prefixParser;
596
597 if (!isInitialized()) {
598 BoolResult res = makeInputCheckFailure("Not initialized (setUpstreamParameters)");
599 hidl_cb(res.success, res.errMsg);
600 fl.setResult(res.success, res.errMsg);
601 }
602 else if (!prefixParser.add(prefix)) {
603 BoolResult res = makeInputCheckFailure(prefixParser.getLastErrAsStr());
604 hidl_cb(res.success, res.errMsg);
605 fl.setResult(res.success, res.errMsg);
606 } else {
607 RET ipaReturn = mIPA->removeDownstream(
608 iface.c_str(),
609 prefixParser.getFirstPrefix());
610 BoolResult res = ipaResultToBoolResult(ipaReturn);
611 hidl_cb(res.success, res.errMsg);
612 fl.setResult(res.success, res.errMsg);
613 }
614
615 mLogs.addLog(fl);
616 return Void();
617 } /* removeDownstream */
618