content: /*
   * Copyright (C) 2017 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.net.ip;
  
  import android.net.INetd;
  import android.net.InterfaceConfigurationParcel;
  import android.net.LinkAddress;
  import android.net.util.SharedLog;
  import android.os.RemoteException;
  import android.os.ServiceSpecificException;
  import android.system.OsConstants;
  
  import java.net.Inet4Address;
  import java.net.InetAddress;
  
  
  /**
   * Encapsulates the multiple IP configuration operations performed on an interface.
   *
   * TODO: refactor/eliminate the redundant ways to set and clear addresses.
   *
   * @hide
   */
  public class InterfaceController {
      private final static boolean DBG = false;
  
      private final String mIfName;
      private final INetd mNetd;
      private final SharedLog mLog;
  
      public InterfaceController(String ifname, INetd netd, SharedLog log) {
          mIfName = ifname;
          mNetd = netd;
          mLog = log;
      }
  
      private boolean setInterfaceAddress(LinkAddress addr) {
          final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
          ifConfig.ifName = mIfName;
          ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
          ifConfig.prefixLength = addr.getPrefixLength();
          ifConfig.hwAddr = "";
          ifConfig.flags = new String[0];
          try {
              mNetd.interfaceSetCfg(ifConfig);
          } catch (RemoteException | ServiceSpecificException e) {
              logError("Setting IPv4 address to %s/%d failed: %s",
                      ifConfig.ipv4Addr, ifConfig.prefixLength, e);
              return false;
          }
          return true;
      }
  
      /**
       * Set the IPv4 address of the interface.
       */
      public boolean setIPv4Address(LinkAddress address) {
          if (!(address.getAddress() instanceof Inet4Address)) {
              return false;
          }
          return setInterfaceAddress(address);
      }
  
      /**
       * Clear the IPv4Address of the interface.
       */
      public boolean clearIPv4Address() {
          return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
      }
  
      private boolean setEnableIPv6(boolean enabled) {
          try {
              mNetd.interfaceSetEnableIPv6(mIfName, enabled);
          } catch (RemoteException | ServiceSpecificException e) {
              logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
              return false;
          }
          return true;
      }
  
      /**
       * Enable IPv6 on the interface.
       */
      public boolean enableIPv6() {
          return setEnableIPv6(true);
      }
  
      /**
       * Disable IPv6 on the interface.
       */
      public boolean disableIPv6() {
          return setEnableIPv6(false);
      }
  
      /**
       * Enable or disable IPv6 privacy extensions on the interface.
       * @param enabled Whether the extensions should be enabled.
       */
      public boolean setIPv6PrivacyExtensions(boolean enabled) {
          try {
              mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
          } catch (RemoteException | ServiceSpecificException e) {
              logError("error %s IPv6 privacy extensions: %s",
                      (enabled ? "enabling" : "disabling"), e);
              return false;
          }
          return true;
      }
  
      /**
       * Set IPv6 address generation mode on the interface.
       *
       * <p>IPv6 should be disabled before changing the mode.
       */
      public boolean setIPv6AddrGenModeIfSupported(int mode) {
          try {
              mNetd.setIPv6AddrGenMode(mIfName, mode);
          } catch (RemoteException e) {
              logError("Unable to set IPv6 addrgen mode: %s", e);
              return false;
          } catch (ServiceSpecificException e) {
              if (e.errorCode != OsConstants.EOPNOTSUPP) {
                  logError("Unable to set IPv6 addrgen mode: %s", e);
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Add an address to the interface.
       */
      public boolean addAddress(LinkAddress addr) {
          return addAddress(addr.getAddress(), addr.getPrefixLength());
      }
  
      /**
       * Add an address to the interface.
       */
      public boolean addAddress(InetAddress ip, int prefixLen) {
          try {
              mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
          } catch (ServiceSpecificException | RemoteException e) {
              logError("failed to add %s/%d: %s", ip, prefixLen, e);
              return false;
          }
          return true;
      }
  
      /**
       * Remove an address from the interface.
       */
      public boolean removeAddress(InetAddress ip, int prefixLen) {
          try {
              mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
          } catch (ServiceSpecificException | RemoteException e) {
              logError("failed to remove %s/%d: %s", ip, prefixLen, e);
              return false;
          }
          return true;
      }
  
      /**
       * Remove all addresses from the interface.
       */
      public boolean clearAllAddresses() {
          try {
              mNetd.interfaceClearAddrs(mIfName);
          } catch (Exception e) {
              logError("Failed to clear addresses: %s", e);
              return false;
          }
          return true;
      }
  
      private void logError(String fmt, Object... args) {
          mLog.e(String.format(fmt, args));
      }
  }
  