Bug 1057091 - Add USB tethring command supporting IPv6 outgoing interface. r=hchang, a=kkuo
authorChuck Lee <chulee@mozilla.com>
Thu, 18 Sep 2014 16:21:50 +0800
changeset 238409 d50110422703de955c36e03e93e007e4d4b5c19e
parent 238408 ea3b70dd2b3fac37d3f0e7c24f075df0e516c44e
child 238410 54ea4f5d43c39469b28aa607e66a44c5a3fd8a96
push id610
push userryanvm@gmail.com
push dateTue, 19 May 2015 01:50:15 +0000
treeherdermozilla-b2g37_v2_2@d50110422703 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershchang, kkuo
bugs1057091
milestone37.0
Bug 1057091 - Add USB tethring command supporting IPv6 outgoing interface. r=hchang, a=kkuo
dom/system/gonk/NetworkUtils.cpp
dom/system/gonk/NetworkUtils.h
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -46,16 +46,21 @@ static const char* SYS_USB_CONFIG_PROPER
 static const char* SYS_USB_STATE_PROPERTY          = "sys.usb.state";
 
 static const char* USB_FUNCTION_RNDIS  = "rndis";
 static const char* USB_FUNCTION_ADB    = "adb";
 
 // Use this command to continue the function chain.
 static const char* DUMMY_COMMAND = "tether status";
 
+// IPV6 Tethering is not supported in AOSP, use the property to
+// identify vendor specific support in IPV6. We can remove this flag
+// once upstream Android support IPV6 in tethering.
+static const char* IPV6_TETHERING = "ro.tethering.ipv6";
+
 // Retry 20 times (2 seconds) for usb state transition.
 static const uint32_t USB_FUNCTION_RETRY_TIMES = 20;
 // Check "sys.usb.state" every 100ms.
 static const uint32_t USB_FUNCTION_RETRY_INTERVAL = 100;
 
 // 1xx - Requested action is proceeding
 static const uint32_t NETD_COMMAND_PROCEEDING   = 100;
 // 2xx - Requested action has been successfully completed
@@ -76,16 +81,17 @@ static const char* INTERFACE_DELIMIT = "
 static const char* USB_CONFIG_DELIMIT = ",";
 static const char* NETD_MESSAGE_DELIMIT = " ";
 
 static const uint32_t BUF_SIZE = 1024;
 
 static const int32_t SUCCESS = 0;
 
 static uint32_t SDK_VERSION;
+static uint32_t SUPPORT_IPV6_TETHERING;
 
 struct IFProperties {
   char gateway[PROPERTY_VALUE_MAX];
   char dns1[PROPERTY_VALUE_MAX];
   char dns2[PROPERTY_VALUE_MAX];
 };
 
 struct CurrentCommand {
@@ -196,39 +202,43 @@ const CommandFunc NetworkUtils::sUSBEnab
   NetworkUtils::enableNat,
   NetworkUtils::setIpForwardingEnabled,
   NetworkUtils::tetherInterface,
   NetworkUtils::addInterfaceToLocalNetwork,
   NetworkUtils::addRouteToLocalNetwork,
   NetworkUtils::tetheringStatus,
   NetworkUtils::startTethering,
   NetworkUtils::setDnsForwarders,
+  NetworkUtils::addUpstreamInterface,
   NetworkUtils::usbTetheringSuccess
 };
 
 const CommandFunc NetworkUtils::sUSBDisableChain[] = {
   NetworkUtils::untetherInterface,
   NetworkUtils::removeInterfaceFromLocalNetwork,
   NetworkUtils::preTetherInterfaceList,
   NetworkUtils::postTetherInterfaceList,
+  NetworkUtils::removeUpstreamInterface,
   NetworkUtils::disableNat,
   NetworkUtils::setIpForwardingEnabled,
   NetworkUtils::stopTethering,
   NetworkUtils::usbTetheringSuccess
 };
 
 const CommandFunc NetworkUtils::sUSBFailChain[] = {
   NetworkUtils::stopSoftAP,
   NetworkUtils::setIpForwardingEnabled,
   NetworkUtils::stopTethering
 };
 
 const CommandFunc NetworkUtils::sUpdateUpStreamChain[] = {
   NetworkUtils::cleanUpStream,
+  NetworkUtils::removeUpstreamInterface,
   NetworkUtils::createUpStream,
+  NetworkUtils::addUpstreamInterface,
   NetworkUtils::updateUpStreamSuccess
 };
 
 const CommandFunc NetworkUtils::sStartDhcpServerChain[] = {
   NetworkUtils::setInterfaceUp,
   NetworkUtils::startTethering,
   NetworkUtils::setDhcpServerSuccess
 };
@@ -808,16 +818,89 @@ void NetworkUtils::postTetherInterfaceLi
   char buf[BUF_SIZE];
   NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
   memcpy(buf, reason.get(), reason.Length() + 1);
   split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList));
 
   doCommand(command, aChain, aCallback);
 }
 
+bool isCommandChainIPv6(CommandChain* aChain, const char *externalInterface) {
+  // Check by gateway address
+  if (getIpType(GET_CHAR(mGateway)) == AF_INET6) {
+    return true;
+  }
+
+  uint32_t length = GET_FIELD(mGateways).Length();
+  for (uint32_t i = 0; i < length; i++) {
+    NS_ConvertUTF16toUTF8 autoGateway(GET_FIELD(mGateways)[i]);
+    if(getIpType(autoGateway.get()) == AF_INET6) {
+      return true;
+    }
+  }
+
+  // Check by external inteface address
+  FILE *file = fopen("/proc/net/if_inet6", "r");
+  if (!file) {
+    return false;
+  }
+
+  bool isIPv6 = false;
+  char interface[32];
+  while(fscanf(file, "%*s %*s %*s %*s %*s %32s", interface)) {
+    if (strcmp(interface, externalInterface) == 0) {
+      isIPv6 = true;
+      break;
+    }
+  }
+
+  fclose(file);
+  return isIPv6;
+}
+
+void NetworkUtils::addUpstreamInterface(CommandChain* aChain,
+                                        CommandCallback aCallback,
+                                        NetworkResultOptions& aResult)
+{
+  nsCString interface(GET_CHAR(mExternalIfname));
+  if (!interface.get()[0]) {
+    interface = GET_CHAR(mCurExternalIfname);
+  }
+
+  if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) {
+    aCallback(aChain, false, aResult);
+    return;
+  }
+
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add_upstream %s",
+           interface.get());
+  doCommand(command, aChain, aCallback);
+}
+
+void NetworkUtils::removeUpstreamInterface(CommandChain* aChain,
+                                           CommandCallback aCallback,
+                                           NetworkResultOptions& aResult)
+{
+  nsCString interface(GET_CHAR(mExternalIfname));
+  if (!interface.get()[0]) {
+    interface = GET_CHAR(mPreExternalIfname);
+  }
+
+  if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) {
+    aCallback(aChain, false, aResult);
+    return;
+  }
+
+  char command[MAX_COMMAND_SIZE];
+  snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove_upstream %s",
+           interface.get());
+  doCommand(command, aChain, aCallback);
+}
+
 void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain,
                                           CommandCallback aCallback,
                                           NetworkResultOptions& aResult)
 {
   char command[MAX_COMMAND_SIZE];
 
   if (GET_FIELD(mEnable)) {
     snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd enable");
@@ -1477,16 +1560,19 @@ NetworkUtils::NetworkUtils(MessageCallba
  : mMessageCallback(aCallback)
 {
   mNetUtils = new NetUtils();
 
   char value[PROPERTY_VALUE_MAX];
   property_get("ro.build.version.sdk", value, nullptr);
   SDK_VERSION = atoi(value);
 
+  property_get(IPV6_TETHERING, value, "0");
+  SUPPORT_IPV6_TETHERING = atoi(value);
+
   gNetworkUtils = this;
 }
 
 NetworkUtils::~NetworkUtils()
 {
 }
 
 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -359,16 +359,18 @@ private:
   static void removeQuota(PARAMS);
   static void setAlarm(PARAMS);
   static void setInterfaceUp(PARAMS);
   static void tetherInterface(PARAMS);
   static void addInterfaceToLocalNetwork(PARAMS);
   static void addRouteToLocalNetwork(PARAMS);
   static void preTetherInterfaceList(PARAMS);
   static void postTetherInterfaceList(PARAMS);
+  static void addUpstreamInterface(PARAMS);
+  static void removeUpstreamInterface(PARAMS);
   static void setIpForwardingEnabled(PARAMS);
   static void tetheringStatus(PARAMS);
   static void stopTethering(PARAMS);
   static void startTethering(PARAMS);
   static void untetherInterface(PARAMS);
   static void removeInterfaceFromLocalNetwork(PARAMS);
   static void setDnsForwarders(PARAMS);
   static void enableNat(PARAMS);