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.

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

mercurial