LowpanInterface.java revision 325b7f5a066bc69c2ad32e1290274d18f40e423b
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net.lowpan; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.net.IpPrefix; 22import android.os.Handler; 23import android.os.IBinder; 24import android.os.RemoteException; 25import android.os.ServiceSpecificException; 26import android.util.Log; 27import java.util.HashMap; 28import java.util.Map; 29import java.util.Set; 30 31/** 32 * Class for managing a specific Low-power Wireless Personal Area Network (LoWPAN) interface. 33 * 34 * @hide 35 */ 36// @SystemApi 37public class LowpanInterface { 38 private static final String TAG = LowpanInterface.class.getSimpleName(); 39 40 /** Detached role. The interface is not currently attached to a network. */ 41 public static final String ROLE_DETACHED = "detached"; 42 43 /** End-device role. End devices do not route traffic for other nodes. */ 44 public static final String ROLE_END_DEVICE = "end-device"; 45 46 /** Router role. Routers help route traffic around the mesh network. */ 47 public static final String ROLE_ROUTER = "router"; 48 49 /** 50 * Sleepy End-Device role. 51 * 52 * <p>End devices with this role are nominally asleep, waking up periodically to check in with 53 * their parent to see if there are packets destined for them. Such devices are capable of 54 * extraordinarilly low power consumption, but packet latency can be on the order of dozens of 55 * seconds(depending on how the node is configured). 56 */ 57 public static final String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device"; 58 59 /** 60 * Sleepy-router role. 61 * 62 * <p>Routers with this role are nominally asleep, waking up periodically to check in with other 63 * routers and their children. 64 */ 65 public static final String ROLE_SLEEPY_ROUTER = "sleepy-router"; 66 67 /** TODO: doc */ 68 public static final String ROLE_LEADER = "leader"; 69 70 /** TODO: doc */ 71 public static final String ROLE_COORDINATOR = "coordinator"; 72 73 /** 74 * Offline state. 75 * 76 * <p>This is the initial state of the LoWPAN interface when the underlying driver starts. In 77 * this state the NCP is idle and not connected to any network. 78 * 79 * <p>This state can be explicitly entered by calling {@link #reset()}, {@link #leave()}, or 80 * <code>setUp(false)</code>, with the later two only working if we were not previously in the 81 * {@link #STATE_FAULT} state. 82 * 83 * @see #getState() 84 * @see #STATE_FAULT 85 */ 86 public static final String STATE_OFFLINE = "offline"; 87 88 /** 89 * Commissioning state. 90 * 91 * <p>The interface enters this state after a call to {@link #startCommissioningSession()}. This 92 * state may only be entered directly from the {@link #STATE_OFFLINE} state. 93 * 94 * @see #startCommissioningSession() 95 * @see #getState() 96 * @hide 97 */ 98 public static final String STATE_COMMISSIONING = "commissioning"; 99 100 /** 101 * Attaching state. 102 * 103 * <p>The interface enters this state when it starts the process of trying to find other nodes 104 * so that it can attach to any pre-existing network fragment, or when it is in the process of 105 * calculating the optimal values for unspecified parameters when forming a new network. 106 * 107 * <p>The interface may stay in this state for a prolonged period of time (or may spontaneously 108 * enter this state from {@link #STATE_ATTACHED}) if the underlying network technology is 109 * heirarchical (like ZigBeeIP) or if the device role is that of an "end-device" ({@link 110 * #ROLE_END_DEVICE} or {@link #ROLE_SLEEPY_END_DEVICE}). This is because such roles cannot 111 * create their own network fragments. 112 * 113 * @see #STATE_ATTACHED 114 * @see #getState() 115 */ 116 public static final String STATE_ATTACHING = "attaching"; 117 118 /** 119 * Attached state. 120 * 121 * <p>The interface enters this state from {@link #STATE_ATTACHING} once it is actively 122 * participating on a network fragment. 123 * 124 * @see #STATE_ATTACHING 125 * @see #getState() 126 */ 127 public static final String STATE_ATTACHED = "attached"; 128 129 /** 130 * Fault state. 131 * 132 * <p>The interface will enter this state when the driver has detected some sort of problem from 133 * which it was not immediately able to recover. 134 * 135 * <p>This state can be entered spontaneously from any other state. Calling {@link #reset} will 136 * cause the device to return to the {@link #STATE_OFFLINE} state. 137 * 138 * @see #getState 139 * @see #STATE_OFFLINE 140 */ 141 public static final String STATE_FAULT = "fault"; 142 143 /** 144 * Network type for Thread 1.x networks. 145 * 146 * @see android.net.lowpan.LowpanIdentity#getType 147 * @see #getLowpanIdentity 148 * @hide 149 */ 150 public static final String NETWORK_TYPE_THREAD = "org.threadgroup.thread.v1"; 151 152 /** 153 * Network type for ZigBeeIP 1.x networks. 154 * 155 * @see android.net.lowpan.LowpanIdentity#getType 156 * @see #getLowpanIdentity 157 * @hide 158 */ 159 public static final String NETWORK_TYPE_ZIGBEE_IP = "org.zigbee.zigbeeip.v1"; 160 161 private static final String NETWORK_PROPERTY_KEYS[] = { 162 LowpanProperties.KEY_NETWORK_NAME.getName(), 163 LowpanProperties.KEY_NETWORK_PANID.getName(), 164 LowpanProperties.KEY_NETWORK_XPANID.getName(), 165 LowpanProperties.KEY_CHANNEL.getName() 166 }; 167 168 /** 169 * Callback base class for LowpanInterface 170 * 171 * @hide 172 */ 173 // @SystemApi 174 public abstract static class Callback { 175 public void onConnectedChanged(boolean value) {} 176 177 public void onEnabledChanged(boolean value) {} 178 179 public void onUpChanged(boolean value) {} 180 181 public void onRoleChanged(@NonNull String value) {} 182 183 public void onStateChanged(@NonNull String state) {} 184 185 public void onLowpanIdentityChanged(@NonNull LowpanIdentity value) {} 186 187 /** @hide */ 188 public void onPropertiesChanged(@NonNull Map properties) {} 189 } 190 191 private ILowpanInterface mBinder; 192 private final HashMap<Integer, ILowpanInterfaceListener> mListenerMap = new HashMap<>(); 193 194 /** Map between IBinder identity hashes and LowpanInstance objects. */ 195 private static final HashMap<Integer, LowpanInterface> sInstanceMap = new HashMap<>(); 196 197 private LowpanInterface(IBinder binder) { 198 mBinder = ILowpanInterface.Stub.asInterface(binder); 199 } 200 201 /** 202 * Get the LowpanInterface object associated with this IBinder. Returns null if this IBinder 203 * does not implement the appropriate interface. 204 * 205 * @hide 206 */ 207 @NonNull 208 public static final LowpanInterface from(IBinder binder) { 209 Integer hashCode = Integer.valueOf(System.identityHashCode(binder)); 210 LowpanInterface instance; 211 212 synchronized (sInstanceMap) { 213 instance = sInstanceMap.get(hashCode); 214 215 if (instance == null) { 216 instance = new LowpanInterface(binder); 217 sInstanceMap.put(hashCode, instance); 218 } 219 } 220 221 return instance; 222 } 223 224 /** {@hide} */ 225 public static final LowpanInterface from(ILowpanInterface iface) { 226 return from(iface.asBinder()); 227 } 228 229 /** {@hide} */ 230 public static final LowpanInterface getInterfaceFromBinder(IBinder binder) { 231 return from(binder); 232 } 233 234 /** 235 * Returns the IBinder object associated with this interface. 236 * 237 * @hide 238 */ 239 public IBinder getBinder() { 240 return mBinder.asBinder(); 241 } 242 243 private static void throwAsPublicException(Throwable t) throws LowpanException { 244 LowpanException.throwAsPublicException(t); 245 } 246 247 // Private Property Helpers 248 249 void setProperties(Map properties) throws LowpanException { 250 try { 251 mBinder.setProperties(properties); 252 253 } catch (RemoteException x) { 254 // Catch and ignore all binder exceptions 255 Log.e(TAG, x.toString()); 256 257 } catch (ServiceSpecificException x) { 258 throwAsPublicException(x); 259 } 260 } 261 262 @NonNull 263 Map<String, Object> getProperties(String keys[]) throws LowpanException { 264 try { 265 return mBinder.getProperties(keys); 266 } catch (RemoteException x) { 267 // Catch and ignore all binder exceptions 268 Log.e(TAG, x.toString()); 269 } catch (ServiceSpecificException x) { 270 throwAsPublicException(x); 271 } 272 return new HashMap(); 273 } 274 275 /** @hide */ 276 public <T> void setProperty(LowpanProperty<T> key, T value) throws LowpanException { 277 HashMap<String, T> prop = new HashMap<>(); 278 prop.put(key.getName(), value); 279 setProperties(prop); 280 } 281 282 /** @hide */ 283 @Nullable 284 public <T> T getProperty(LowpanProperty<T> key) throws LowpanException { 285 Map<String, Object> map = getProperties(new String[] {key.getName()}); 286 if (map != null && !map.isEmpty()) { 287 // We know there is only one value. 288 return (T) map.values().iterator().next(); 289 } 290 return null; 291 } 292 293 @Nullable 294 <T> String getPropertyAsString(LowpanProperty<T> key) throws LowpanException { 295 try { 296 return mBinder.getPropertyAsString(key.getName()); 297 } catch (RemoteException x) { 298 // Catch and ignore all binder exceptions 299 Log.e(TAG, x.toString()); 300 } catch (ServiceSpecificException x) { 301 throwAsPublicException(x); 302 } 303 return null; 304 } 305 306 int getPropertyAsInt(LowpanProperty<Integer> key) throws LowpanException { 307 Integer value = getProperty(key); 308 return (value != null) ? value : 0; 309 } 310 311 boolean getPropertyAsBoolean(LowpanProperty<Boolean> key) throws LowpanException { 312 Boolean value = getProperty(key); 313 return (value != null) ? value : false; 314 } 315 316 // Public Actions 317 318 /** 319 * Form a new network with the given network information optional credential. Unspecified fields 320 * in the network information will be filled in with reasonable values. If the network 321 * credential is unspecified, one will be generated automatically. 322 * 323 * <p>This method will block until either the network was successfully formed or an error 324 * prevents the network form being formed. 325 * 326 * <p>Upon success, the interface will be up and attached to the newly formed network. 327 * 328 * @see #join(LowpanProvision) 329 */ 330 public void form(@NonNull LowpanProvision provision) throws LowpanException { 331 try { 332 Map<String, Object> parameters = new HashMap(); 333 provision.addToMap(parameters); 334 mBinder.form(parameters); 335 } catch (RemoteException x) { 336 throwAsPublicException(x); 337 } catch (ServiceSpecificException x) { 338 throwAsPublicException(x); 339 } 340 } 341 342 /** 343 * Attempts to join a new network with the given network information. This method will block 344 * until either the network was successfully joined or an error prevented the network from being 345 * formed. Upon success, the interface will be up and attached to the newly joined network. 346 * 347 * <p>Note that “joining” is distinct from “attaching”: Joining requires at least one other peer 348 * device to be present in order for the operation to complete successfully. 349 */ 350 public void join(@NonNull LowpanProvision provision) throws LowpanException { 351 try { 352 Map<String, Object> parameters = new HashMap(); 353 provision.addToMap(parameters); 354 mBinder.join(parameters); 355 } catch (RemoteException x) { 356 throwAsPublicException(x); 357 } catch (ServiceSpecificException x) { 358 throwAsPublicException(x); 359 } 360 } 361 362 /** 363 * Attaches to the network described by identity and credential. This is similar to {@link 364 * #join}, except that (assuming the identity and credential are valid) it will always succeed 365 * and provision the interface, even if there are no peers nearby. 366 * 367 * <p>This method will block execution until the operation has completed. 368 */ 369 public void attach(@NonNull LowpanProvision provision) throws LowpanException { 370 if (ROLE_DETACHED.equals(getRole())) { 371 Map<String, Object> parameters = new HashMap(); 372 provision.addToMap(parameters); 373 setProperties(parameters); 374 setUp(true); 375 } else { 376 throw new LowpanException(LowpanException.LOWPAN_ALREADY); 377 } 378 } 379 380 /** 381 * Bring down the network interface and forget all non-volatile details about the current 382 * network. 383 * 384 * <p>This method will block execution until the operation has completed. 385 */ 386 public void leave() throws LowpanException { 387 try { 388 mBinder.leave(); 389 } catch (RemoteException x) { 390 throwAsPublicException(x); 391 } catch (ServiceSpecificException x) { 392 throwAsPublicException(x); 393 } 394 } 395 396 /** 397 * Start a new commissioning session. Will fail if the interface is attached to a network or if 398 * the interface is disabled. 399 */ 400 public @NonNull LowpanCommissioningSession startCommissioningSession( 401 @NonNull LowpanBeaconInfo beaconInfo) throws LowpanException { 402 403 /* TODO: Implement startCommissioningSession */ 404 throw new LowpanException(LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED); 405 } 406 407 /** 408 * Reset this network interface as if it has been power cycled. Will bring the network interface 409 * down if it was previously up. Will not erase any non-volatile settings. 410 * 411 * <p>This method will block execution until the operation has completed. 412 * 413 * @hide 414 */ 415 public void reset() throws LowpanException { 416 try { 417 mBinder.reset(); 418 } catch (RemoteException x) { 419 throwAsPublicException(x); 420 } catch (ServiceSpecificException x) { 421 throwAsPublicException(x); 422 } 423 } 424 425 // Public Getters and Setters 426 427 /** 428 * Returns the name of this network interface. 429 * 430 * <p>Will return empty string if this interface is no longer viable. 431 */ 432 @NonNull 433 public String getName() { 434 try { 435 return mBinder.getName(); 436 } catch (RemoteException x) { 437 // Catch and ignore all binder exceptions 438 // when fetching the name. 439 Log.e(TAG, x.toString()); 440 } catch (ServiceSpecificException x) { 441 // Catch and ignore all service-specific exceptions 442 // when fetching the name. 443 Log.e(TAG, x.toString()); 444 } 445 return ""; 446 } 447 448 /** 449 * Indicates if the interface is enabled or disabled. 450 * 451 * @see #setEnabled 452 * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED 453 */ 454 public boolean isEnabled() { 455 try { 456 return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_ENABLED); 457 } catch (LowpanException x) { 458 return false; 459 } 460 } 461 462 /** 463 * Enables or disables the LoWPAN interface. When disabled, the interface is put into a 464 * low-power state and all commands that require the NCP to be queried will fail with {@link 465 * android.net.lowpan.LowpanException#LOWPAN_DISABLED}. 466 * 467 * @see #isEnabled 468 * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED 469 * @hide 470 */ 471 public void setEnabled(boolean enabled) throws LowpanException { 472 setProperty(LowpanProperties.KEY_INTERFACE_ENABLED, enabled); 473 } 474 475 /** 476 * Indicates if the network interface is up or down. 477 * 478 * @hide 479 */ 480 public boolean isUp() { 481 try { 482 return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_UP); 483 } catch (LowpanException x) { 484 return false; 485 } 486 } 487 488 /** 489 * Bring up or shut down the network interface. 490 * 491 * <p>This method brings up or shuts down the network interface, attaching or (gracefully) 492 * detaching from the currently configured LoWPAN network as appropriate. 493 * 494 * @hide 495 */ 496 public void setUp(boolean interfaceUp) throws LowpanException { 497 setProperty(LowpanProperties.KEY_INTERFACE_UP, interfaceUp); 498 } 499 500 /** 501 * Indicates if there is at least one peer in range. 502 * 503 * @return <code>true</code> if we have at least one other peer in range, <code>false</code> 504 * otherwise. 505 */ 506 public boolean isConnected() { 507 try { 508 return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_CONNECTED); 509 } catch (LowpanException x) { 510 return false; 511 } 512 } 513 514 /** 515 * Indicates if this interface is currently commissioned onto an existing network. If the 516 * interface is commissioned, the interface may be brought up using setUp(). 517 */ 518 public boolean isCommissioned() { 519 try { 520 return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_COMMISSIONED); 521 } catch (LowpanException x) { 522 return false; 523 } 524 } 525 526 /** 527 * Get interface state 528 * 529 * <h3>State Diagram</h3> 530 * 531 * <img src="LowpanInterface-1.png" /> 532 * 533 * @return The current state of the interface. 534 * @see #STATE_OFFLINE 535 * @see #STATE_COMMISSIONING 536 * @see #STATE_ATTACHING 537 * @see #STATE_ATTACHED 538 * @see #STATE_FAULT 539 */ 540 public String getState() { 541 try { 542 return getProperty(LowpanProperties.KEY_INTERFACE_STATE); 543 } catch (LowpanException x) { 544 Log.e(TAG, x.toString()); 545 return STATE_FAULT; 546 } 547 } 548 549 /** TODO: doc */ 550 public LowpanIdentity getLowpanIdentity() { 551 LowpanIdentity.Builder builder = new LowpanIdentity.Builder(); 552 try { 553 builder.updateFromMap(getProperties(NETWORK_PROPERTY_KEYS)); 554 } catch (LowpanException x) { 555 // We ignore all LoWPAN-specitic exceptions here. 556 } 557 558 return builder.build(); 559 } 560 561 /** 562 * TODO: doc 563 * 564 * @hide 565 */ 566 public void setLowpanIdentity(LowpanIdentity network) throws LowpanException { 567 Map<String, Object> map = new HashMap(); 568 LowpanIdentity.addToMap(map, network); 569 setProperties(map); 570 } 571 572 /** TODO: doc */ 573 @NonNull 574 public String getRole() { 575 String role = null; 576 577 try { 578 role = getProperty(LowpanProperties.KEY_NETWORK_ROLE); 579 } catch (LowpanException x) { 580 // We ignore all LoWPAN-specitic exceptions here. 581 Log.e(TAG, x.toString()); 582 } 583 584 if (role == null) { 585 role = ROLE_DETACHED; 586 } 587 588 return role; 589 } 590 591 /** TODO: doc */ 592 @Nullable 593 public LowpanCredential getLowpanCredential() { 594 LowpanCredential credential = null; 595 596 try { 597 Integer keyIndex = getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX); 598 599 if (keyIndex == null) { 600 credential = 601 LowpanCredential.createMasterKey( 602 getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY)); 603 } else { 604 credential = 605 LowpanCredential.createMasterKey( 606 getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY), 607 keyIndex.intValue()); 608 } 609 } catch (LowpanException x) { 610 // We ignore all LoWPAN-specitic exceptions here. 611 Log.e(TAG, x.toString()); 612 } 613 614 return credential; 615 } 616 617 /** 618 * TODO: doc 619 * 620 * @hide 621 */ 622 public void setLowpanCredential(LowpanCredential networkCredential) throws LowpanException { 623 Map<String, Object> map = new HashMap(); 624 networkCredential.addToMap(map); 625 setProperties(map); 626 } 627 628 // Listener Support 629 630 /** 631 * Registers a subclass of {@link LowpanInterface.Callback} to receive events. 632 * 633 * @param cb Subclass of {@link LowpanInterface.Callback} which will receive events. 634 * @param handler If not <code>null</code>, events will be dispatched via the given handler 635 * object. If <code>null</code>, the thread upon which events will be dispatched is 636 * unspecified. 637 * @see #registerCallback(Callback) 638 * @see #unregisterCallback(Callback) 639 */ 640 public void registerCallback(@NonNull Callback cb, @Nullable Handler handler) { 641 ILowpanInterfaceListener.Stub listenerBinder = 642 new ILowpanInterfaceListener.Stub() { 643 public void onPropertiesChanged(Map properties) { 644 Runnable runnable = 645 new Runnable() { 646 @Override 647 public void run() { 648 for (String key : (Set<String>) properties.keySet()) { 649 Object value = properties.get(key); 650 switch (key) { 651 case ILowpanInterface.KEY_INTERFACE_ENABLED: 652 cb.onEnabledChanged( 653 ((Boolean) value).booleanValue()); 654 break; 655 case ILowpanInterface.KEY_INTERFACE_UP: 656 cb.onUpChanged( 657 ((Boolean) value).booleanValue()); 658 break; 659 case ILowpanInterface.KEY_INTERFACE_CONNECTED: 660 cb.onConnectedChanged( 661 ((Boolean) value).booleanValue()); 662 break; 663 case ILowpanInterface.KEY_INTERFACE_STATE: 664 cb.onStateChanged((String) value); 665 break; 666 case ILowpanInterface.KEY_NETWORK_NAME: 667 case ILowpanInterface.KEY_NETWORK_PANID: 668 case ILowpanInterface.KEY_NETWORK_XPANID: 669 case ILowpanInterface.KEY_CHANNEL: 670 cb.onLowpanIdentityChanged(getLowpanIdentity()); 671 break; 672 case ILowpanInterface.KEY_NETWORK_ROLE: 673 cb.onRoleChanged(value.toString()); 674 break; 675 } 676 } 677 cb.onPropertiesChanged(properties); 678 } 679 }; 680 681 if (handler != null) { 682 handler.post(runnable); 683 } else { 684 runnable.run(); 685 } 686 } 687 }; 688 try { 689 mBinder.addListener(listenerBinder); 690 } catch (RemoteException x) { 691 // Log and ignore. If this happens, this interface 692 // is likely dead anyway. 693 Log.e(TAG, x.toString()); 694 } 695 synchronized (mListenerMap) { 696 mListenerMap.put(System.identityHashCode(cb), listenerBinder); 697 } 698 } 699 700 /** 701 * Registers a subclass of {@link LowpanInterface.Callback} to receive events. 702 * 703 * <p>The thread upon which events will be dispatched is unspecified. 704 * 705 * @param cb Subclass of {@link LowpanInterface.Callback} which will receive events. 706 * @see #registerCallback(Callback, Handler) 707 * @see #unregisterCallback(Callback) 708 */ 709 public void registerCallback(Callback cb) { 710 registerCallback(cb, null); 711 } 712 713 /** 714 * Unregisters a previously registered callback class. 715 * 716 * @param cb Subclass of {@link LowpanInterface.Callback} which was previously registered to 717 * receive events. 718 * @see #registerCallback(Callback, Handler) 719 * @see #registerCallback(Callback) 720 */ 721 public void unregisterCallback(Callback cb) { 722 int hashCode = System.identityHashCode(cb); 723 synchronized (mListenerMap) { 724 ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode); 725 726 if (listenerBinder != null) { 727 mListenerMap.remove(hashCode); 728 729 try { 730 mBinder.removeListener(listenerBinder); 731 } catch (RemoteException x) { 732 // Catch and ignore all binder exceptions 733 Log.e(TAG, x.toString()); 734 } 735 } 736 } 737 } 738 739 // Active and Passive Scanning 740 741 /** 742 * Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface. 743 * 744 * <p>This method allocates a new unique object for each call. 745 * 746 * @see android.net.lowpan.LowpanScanner 747 */ 748 public @NonNull LowpanScanner createScanner() { 749 return new LowpanScanner(mBinder); 750 } 751 752 // Route Management 753 754 /** 755 * Advertise the given IP prefix as an on-mesh prefix. 756 * 757 * @hide 758 */ 759 public void addOnMeshPrefix(IpPrefix prefix, int flags) throws LowpanException { 760 try { 761 mBinder.addOnMeshPrefix(prefix, flags); 762 } catch (RemoteException x) { 763 throwAsPublicException(x); 764 } catch (ServiceSpecificException x) { 765 throwAsPublicException(x); 766 } 767 } 768 769 /** 770 * Remove an IP prefix previously advertised by this device from the list of advertised on-mesh 771 * prefixes. 772 * 773 * @hide 774 */ 775 public void removeOnMeshPrefix(IpPrefix prefix) { 776 try { 777 mBinder.removeOnMeshPrefix(prefix); 778 } catch (RemoteException x) { 779 // Catch and ignore all binder exceptions 780 Log.e(TAG, x.toString()); 781 } catch (ServiceSpecificException x) { 782 // Catch and ignore all service exceptions 783 Log.e(TAG, x.toString()); 784 } 785 } 786 787 /** 788 * Advertise this device to other devices on the mesh network as having a specific route to the 789 * given network. This device will then receive forwarded traffic for that network. 790 * 791 * @hide 792 */ 793 public void addExternalRoute(IpPrefix prefix, int flags) throws LowpanException { 794 try { 795 mBinder.addExternalRoute(prefix, flags); 796 } catch (RemoteException x) { 797 throwAsPublicException(x); 798 } catch (ServiceSpecificException x) { 799 throwAsPublicException(x); 800 } 801 } 802 803 /** 804 * Revoke a previously advertised specific route to the given network. 805 * 806 * @hide 807 */ 808 public void removeExternalRoute(IpPrefix prefix) { 809 try { 810 mBinder.removeExternalRoute(prefix); 811 } catch (RemoteException x) { 812 // Catch and ignore all binder exceptions 813 Log.e(TAG, x.toString()); 814 } catch (ServiceSpecificException x) { 815 // Catch and ignore all service exceptions 816 Log.e(TAG, x.toString()); 817 } 818 } 819} 820