dom/wifi/WifiUtils.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "WifiUtils.h"
     6 #include <dlfcn.h>
     7 #include <errno.h>
     8 #include <cutils/properties.h>
     9 #include "prinit.h"
    10 #include "js/CharacterEncoding.h"
    11 #include "mozilla/dom/network/NetUtils.h"
    13 using namespace mozilla::dom;
    15 #define BUFFER_SIZE        4096
    16 #define COMMAND_SIZE       256
    17 #define PROPERTY_VALUE_MAX 80
    19 // Intentionally not trying to dlclose() this handle. That's playing
    20 // Russian roulette with security bugs.
    21 static void* sWifiLib;
    22 static PRCallOnceType sInitWifiLib;
    24 static PRStatus
    25 InitWifiLib()
    26 {
    27   sWifiLib = dlopen("/system/lib/libhardware_legacy.so", RTLD_LAZY);
    28   // We might fail to open the hardware lib. That's OK.
    29   return PR_SUCCESS;
    30 }
    32 static void*
    33 GetSharedLibrary()
    34 {
    35   PR_CallOnce(&sInitWifiLib, InitWifiLib);
    36   return sWifiLib;
    37 }
    39 static bool
    40 GetWifiP2pSupported()
    41 {
    42   char propP2pSupported[PROPERTY_VALUE_MAX];
    43   property_get("ro.moz.wifi.p2p_supported", propP2pSupported, "0");
    44   return (0 == strcmp(propP2pSupported, "1"));
    45 }
    47 // This is the same algorithm as in InflateUTF8StringToBuffer with Copy and
    48 // while ignoring invalids.
    49 // https://mxr.mozilla.org/mozilla-central/source/js/src/vm/CharacterEncoding.cpp#231
    51 static const uint32_t REPLACE_UTF8 = 0xFFFD;
    53 void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
    54 {
    55   JS::UTF8Chars src(aInput, aLength);
    57   char16_t dst[aLength]; // Allocating for worst case.
    59   // First, count how many jschars need to be in the inflated string.
    60   // |i| is the index into |src|, and |j| is the the index into |dst|.
    61   size_t srclen = src.length();
    62   uint32_t j = 0;
    63   for (uint32_t i = 0; i < srclen; i++, j++) {
    64     uint32_t v = uint32_t(src[i]);
    65     if (!(v & 0x80)) {
    66       // ASCII code unit.  Simple copy.
    67       dst[j] = char16_t(v);
    68     } else {
    69       // Non-ASCII code unit.  Determine its length in bytes (n).
    70       uint32_t n = 1;
    71       while (v & (0x80 >> n))
    72         n++;
    74   #define INVALID(report, arg, n2)                          \
    75       do {                                                  \
    76         n = n2;                                             \
    77         goto invalidMultiByteCodeUnit;                      \
    78       } while (0)
    80       // Check the leading byte.
    81       if (n < 2 || n > 4)
    82         INVALID(ReportInvalidCharacter, i, 1);
    84       // Check that |src| is large enough to hold an n-byte code unit.
    85       if (i + n > srclen)
    86         INVALID(ReportBufferTooSmall, /* dummy = */ 0, 1);
    88       // Check the second byte.  From Unicode Standard v6.2, Table 3-7
    89       // Well-Formed UTF-8 Byte Sequences.
    90       if ((v == 0xE0 && ((uint8_t)src[i + 1] & 0xE0) != 0xA0) ||  // E0 A0~BF
    91         (v == 0xED && ((uint8_t)src[i + 1] & 0xE0) != 0x80) ||  // ED 80~9F
    92         (v == 0xF0 && ((uint8_t)src[i + 1] & 0xF0) == 0x80) ||  // F0 90~BF
    93         (v == 0xF4 && ((uint8_t)src[i + 1] & 0xF0) != 0x80))    // F4 80~8F
    94       {
    95         INVALID(ReportInvalidCharacter, i, 1);
    96       }
    98       // Check the continuation bytes.
    99       for (uint32_t m = 1; m < n; m++)
   100         if ((src[i + m] & 0xC0) != 0x80)
   101           INVALID(ReportInvalidCharacter, i, m);
   103       // Determine the code unit's length in jschars and act accordingly.
   104       v = JS::Utf8ToOneUcs4Char((uint8_t *)&src[i], n);
   105       if (v < 0x10000) {
   106         // The n-byte UTF8 code unit will fit in a single jschar.
   107         dst[j] = jschar(v);
   108       } else {
   109         v -= 0x10000;
   110         if (v <= 0xFFFFF) {
   111           // The n-byte UTF8 code unit will fit in two jschars.
   112           dst[j] = jschar((v >> 10) + 0xD800);
   113           j++;
   114           dst[j] = jschar((v & 0x3FF) + 0xDC00);
   115         } else {
   116           // The n-byte UTF8 code unit won't fit in two jschars.
   117           INVALID(ReportTooBigCharacter, v, 1);
   118         }
   119       }
   121     invalidMultiByteCodeUnit:
   122       // Move i to the last byte of the multi-byte code unit;  the loop
   123       // header will do the final i++ to move to the start of the next
   124       // code unit.
   125       i += n - 1;
   126     }
   127   }
   129   dst[j] = 0;
   130   aOut = dst;
   131 }
   133 // Helper to check we have loaded the hardware shared library.
   134 #define CHECK_HWLIB(ret)                                                      \
   135   void* hwLib = GetSharedLibrary();                                           \
   136   if (!hwLib) {                                                               \
   137     NS_WARNING("No /system/lib/libhardware_legacy.so");                       \
   138     return ret;                                                               \
   139   }
   141 #define DEFAULT_IMPL(name, ret, args...) \
   142   DEFINE_DLFUNC(name, ret, args...)      \
   143   ret do_##name(args) {                  \
   144     USE_DLFUNC(name)                     \
   145     return name(args);                   \
   146   }
   148 // ICS implementation.
   149 class ICSWpaSupplicantImpl : public WpaSupplicantImpl
   150 {
   151 public:
   152   DEFAULT_IMPL(wifi_load_driver, int32_t, )
   153   DEFAULT_IMPL(wifi_unload_driver, int32_t, )
   155   DEFINE_DLFUNC(wifi_wait_for_event, int32_t, char*, size_t)
   156   int32_t do_wifi_wait_for_event(const char *iface, char *buf, size_t len) {
   157     USE_DLFUNC(wifi_wait_for_event)
   158     return wifi_wait_for_event(buf, len);
   159   }
   161   DEFINE_DLFUNC(wifi_command, int32_t, const char*, char*, size_t*)
   162   int32_t do_wifi_command(const char* iface, const char* cmd, char* buf, size_t* len) {
   163     USE_DLFUNC(wifi_command)
   164     return wifi_command(cmd, buf, len);
   165   }
   167   DEFINE_DLFUNC(wifi_start_supplicant, int32_t, )
   168   int32_t do_wifi_start_supplicant(int32_t) {
   169     USE_DLFUNC(wifi_start_supplicant)
   170     return wifi_start_supplicant();
   171   }
   173   DEFINE_DLFUNC(wifi_stop_supplicant, int32_t)
   174   int32_t do_wifi_stop_supplicant(int32_t) {
   175     USE_DLFUNC(wifi_stop_supplicant)
   176     return wifi_stop_supplicant();
   177   }
   179   DEFINE_DLFUNC(wifi_connect_to_supplicant, int32_t, )
   180   int32_t do_wifi_connect_to_supplicant(const char* iface) {
   181     USE_DLFUNC(wifi_connect_to_supplicant)
   182     return wifi_connect_to_supplicant();
   183   }
   185   DEFINE_DLFUNC(wifi_close_supplicant_connection, void, )
   186   void do_wifi_close_supplicant_connection(const char* iface) {
   187     USE_DLFUNC(wifi_close_supplicant_connection)
   188     return wifi_close_supplicant_connection();
   189   }
   190 };
   192 // JB implementation.
   193 // We only redefine the methods that have a different signature than on ICS.
   194 class JBWpaSupplicantImpl : public ICSWpaSupplicantImpl
   195 {
   196 public:
   197   DEFINE_DLFUNC(wifi_wait_for_event, int32_t, const char*, char*, size_t)
   198   int32_t do_wifi_wait_for_event(const char* iface, char* buf, size_t len) {
   199     USE_DLFUNC(wifi_wait_for_event)
   200     return wifi_wait_for_event(iface, buf, len);
   201   }
   203   DEFINE_DLFUNC(wifi_command, int32_t, const char*, const char*, char*, size_t*)
   204   int32_t do_wifi_command(const char* iface, const char* cmd, char* buf, size_t* len) {
   205     USE_DLFUNC(wifi_command)
   206     return wifi_command(iface, cmd, buf, len);
   207   }
   209   DEFINE_DLFUNC(wifi_start_supplicant, int32_t, int32_t)
   210   int32_t do_wifi_start_supplicant(int32_t arg) {
   211     USE_DLFUNC(wifi_start_supplicant)
   212     return wifi_start_supplicant(arg);
   213   }
   215   DEFINE_DLFUNC(wifi_stop_supplicant, int32_t, int32_t)
   216   int32_t do_wifi_stop_supplicant(int32_t arg) {
   217     USE_DLFUNC(wifi_stop_supplicant)
   218     return wifi_stop_supplicant(arg);
   219   }
   221   DEFINE_DLFUNC(wifi_connect_to_supplicant, int32_t, const char*)
   222   int32_t do_wifi_connect_to_supplicant(const char* iface) {
   223     USE_DLFUNC(wifi_connect_to_supplicant)
   224     return wifi_connect_to_supplicant(iface);
   225   }
   227   DEFINE_DLFUNC(wifi_close_supplicant_connection, void, const char*)
   228   void do_wifi_close_supplicant_connection(const char* iface) {
   229     USE_DLFUNC(wifi_close_supplicant_connection)
   230     wifi_close_supplicant_connection(iface);
   231   }
   232 };
   234 // KK implementation.
   235 // We only redefine the methods that have a different signature than on ICS.
   236 class KKWpaSupplicantImpl : public ICSWpaSupplicantImpl
   237 {
   238 public:
   239   DEFINE_DLFUNC(wifi_start_supplicant, int32_t, int32_t)
   240   int32_t do_wifi_start_supplicant(int32_t arg) {
   241     USE_DLFUNC(wifi_start_supplicant)
   242     return wifi_start_supplicant(arg);
   243   }
   245   DEFINE_DLFUNC(wifi_stop_supplicant, int32_t, int32_t)
   246   int32_t do_wifi_stop_supplicant(int32_t arg) {
   247     USE_DLFUNC(wifi_stop_supplicant)
   248     return wifi_stop_supplicant(arg);
   249   }
   251   DEFINE_DLFUNC(wifi_command, int32_t, const char*, char*, size_t*)
   252   int32_t do_wifi_command(const char* iface, const char* cmd, char* buf, size_t* len) {
   253     char command[COMMAND_SIZE];
   254     if (!strcmp(iface, "p2p0")) {
   255       // Commands for p2p0 interface don't need prefix
   256       snprintf(command, COMMAND_SIZE, "%s", cmd);
   257     }
   258     else {
   259       snprintf(command, COMMAND_SIZE, "IFNAME=%s %s", iface, cmd);
   260     }
   261     USE_DLFUNC(wifi_command)
   262     return wifi_command(command, buf, len);
   263   }
   264 };
   266 // Concrete class to use to access the wpa supplicant.
   267 WpaSupplicant::WpaSupplicant()
   268 {
   269   if (NetUtils::SdkVersion() < 16) {
   270     mImpl = new ICSWpaSupplicantImpl();
   271   } else if (NetUtils::SdkVersion() < 19) {
   272     mImpl = new JBWpaSupplicantImpl();
   273   } else {
   274     mImpl = new KKWpaSupplicantImpl();
   275   }
   276   mNetUtils = new NetUtils();
   277 };
   279 void WpaSupplicant::WaitForEvent(nsAString& aEvent, const nsCString& aInterface)
   280 {
   281   CHECK_HWLIB()
   283   char buffer[BUFFER_SIZE];
   284   int32_t ret = mImpl->do_wifi_wait_for_event(aInterface.get(), buffer, BUFFER_SIZE);
   285   CheckBuffer(buffer, ret, aEvent);
   286 }
   288 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
   290 /**
   291  * Make a subnet mask.
   292  */
   293 uint32_t WpaSupplicant::MakeMask(uint32_t len) {
   294   uint32_t mask = 0;
   295   for (uint32_t i = 0; i < len; ++i) {
   296     mask |= (0x80000000 >> i);
   297   }
   298   return ntohl(mask);
   299 }
   301 bool WpaSupplicant::ExecuteCommand(CommandOptions aOptions,
   302                                    WifiResultOptions& aResult,
   303                                    const nsCString& aInterface)
   304 {
   305   CHECK_HWLIB(false)
   306   if (!mNetUtils->GetSharedLibrary()) {
   307     return false;
   308   }
   310   // Always correlate the opaque ids.
   311   aResult.mId = aOptions.mId;
   313   if (aOptions.mCmd.EqualsLiteral("command")) {
   314     size_t len = BUFFER_SIZE - 1;
   315     char buffer[BUFFER_SIZE];
   316     NS_ConvertUTF16toUTF8 request(aOptions.mRequest);
   317     aResult.mStatus = mImpl->do_wifi_command(aInterface.get(), request.get(), buffer, &len);
   318     nsString value;
   319     if (aResult.mStatus == 0) {
   320       if (buffer[len - 1] == '\n') { // remove trailing new lines.
   321         len--;
   322       }
   323       buffer[len] = '\0';
   324       CheckBuffer(buffer, len, value);
   325     }
   326     aResult.mReply = value;
   327   } else if (aOptions.mCmd.EqualsLiteral("close_supplicant_connection")) {
   328     mImpl->do_wifi_close_supplicant_connection(aInterface.get());
   329   } else if (aOptions.mCmd.EqualsLiteral("load_driver")) {
   330     aResult.mStatus = mImpl->do_wifi_load_driver();
   331   } else if (aOptions.mCmd.EqualsLiteral("unload_driver")) {
   332     aResult.mStatus = mImpl->do_wifi_unload_driver();
   333   } else if (aOptions.mCmd.EqualsLiteral("start_supplicant")) {
   334     aResult.mStatus = mImpl->do_wifi_start_supplicant(GetWifiP2pSupported() ? 1 : 0);
   335   } else if (aOptions.mCmd.EqualsLiteral("stop_supplicant")) {
   336     aResult.mStatus = mImpl->do_wifi_stop_supplicant(0);
   337   } else if (aOptions.mCmd.EqualsLiteral("connect_to_supplicant")) {
   338     aResult.mStatus = mImpl->do_wifi_connect_to_supplicant(aInterface.get());
   339   } else if (aOptions.mCmd.EqualsLiteral("ifc_enable")) {
   340     aResult.mStatus = mNetUtils->do_ifc_enable(GET_CHAR(mIfname));
   341   } else if (aOptions.mCmd.EqualsLiteral("ifc_disable")) {
   342     aResult.mStatus = mNetUtils->do_ifc_disable(GET_CHAR(mIfname));
   343   } else if (aOptions.mCmd.EqualsLiteral("ifc_configure")) {
   344     aResult.mStatus = mNetUtils->do_ifc_configure(
   345       GET_CHAR(mIfname), aOptions.mIpaddr, aOptions.mMask,
   346       aOptions.mGateway, aOptions.mDns1, aOptions.mDns2
   347     );
   348   } else if (aOptions.mCmd.EqualsLiteral("ifc_reset_connections")) {
   349     aResult.mStatus = mNetUtils->do_ifc_reset_connections(
   350       GET_CHAR(mIfname), RESET_ALL_ADDRESSES
   351     );
   352   } else if (aOptions.mCmd.EqualsLiteral("dhcp_stop")) {
   353     aResult.mStatus = mNetUtils->do_dhcp_stop(GET_CHAR(mIfname));
   354   } else if (aOptions.mCmd.EqualsLiteral("dhcp_do_request")) {
   355     char ipaddr[PROPERTY_VALUE_MAX];
   356     char gateway[PROPERTY_VALUE_MAX];
   357     uint32_t prefixLength;
   358     char dns1[PROPERTY_VALUE_MAX];
   359     char dns2[PROPERTY_VALUE_MAX];
   360     char server[PROPERTY_VALUE_MAX];
   361     uint32_t lease;
   362     char vendorinfo[PROPERTY_VALUE_MAX];
   363     aResult.mStatus =
   364       mNetUtils->do_dhcp_do_request(GET_CHAR(mIfname),
   365                                     ipaddr,
   366                                     gateway,
   367                                     &prefixLength,
   368                                     dns1,
   369                                     dns2,
   370                                     server,
   371                                     &lease,
   372                                     vendorinfo);
   374     if (aResult.mStatus == -1) {
   375       // Early return since we failed.
   376       return true;
   377     }
   379     aResult.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr);
   380     aResult.mGateway_str = NS_ConvertUTF8toUTF16(gateway);
   381     aResult.mDns1_str = NS_ConvertUTF8toUTF16(dns1);
   382     aResult.mDns2_str = NS_ConvertUTF8toUTF16(dns2);
   383     aResult.mServer_str = NS_ConvertUTF8toUTF16(server);
   384     aResult.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo);
   385     aResult.mLease = lease;
   386     aResult.mMask = MakeMask(prefixLength);
   388     uint32_t inet4; // only support IPv4 for now.
   390 #define INET_PTON(var, field)                                                 \
   391   PR_BEGIN_MACRO                                                              \
   392     inet_pton(AF_INET, var, &inet4);                                          \
   393     aResult.field = inet4;                                                    \
   394   PR_END_MACRO
   396     INET_PTON(ipaddr, mIpaddr);
   397     INET_PTON(gateway, mGateway);
   399     if (dns1[0] != '\0') {
   400       INET_PTON(dns1, mDns1);
   401     }
   403     if (dns2[0] != '\0') {
   404       INET_PTON(dns2, mDns2);
   405     }
   407     INET_PTON(server, mServer);
   409     //aResult.mask_str = netHelpers.ipToString(obj.mask);
   410     char inet_str[64];
   411     if (inet_ntop(AF_INET, &aResult.mMask, inet_str, sizeof(inet_str))) {
   412       aResult.mMask_str = NS_ConvertUTF8toUTF16(inet_str);
   413     }
   414   } else {
   415     NS_WARNING("WpaSupplicant::ExecuteCommand : Unknown command");
   416     printf_stderr("WpaSupplicant::ExecuteCommand : Unknown command: %s",
   417       NS_ConvertUTF16toUTF8(aOptions.mCmd).get());
   418     return false;
   419   }
   421   return true;
   422 }
   424 // Checks the buffer and do the utf processing.
   425 void
   426 WpaSupplicant::CheckBuffer(char* buffer, int32_t length,
   427                            nsAString& aEvent)
   428 {
   429   if (length > 0 && length < BUFFER_SIZE) {
   430     buffer[length] = 0;
   431     LossyConvertUTF8toUTF16(buffer, length, aEvent);
   432   }
   433 }

mercurial