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/. */
8 #include <cutils/properties.h>
10 #include "js/CharacterEncoding.h"
12 using namespace mozilla::dom
;
14 #define BUFFER_SIZE 4096
15 #define COMMAND_SIZE 256
17 // Intentionally not trying to dlclose() this handle. That's playing
18 // Russian roulette with security bugs.
19 static void* sWifiLib
;
20 static PRCallOnceType sInitWifiLib
;
25 sWifiLib
= dlopen("/system/lib/libhardware_legacy.so", RTLD_LAZY
);
26 // We might fail to open the hardware lib. That's OK.
33 PR_CallOnce(&sInitWifiLib
, InitWifiLib
);
40 char propP2pSupported
[PROPERTY_VALUE_MAX
];
41 property_get("ro.moz.wifi.p2p_supported", propP2pSupported
, "0");
42 return (0 == strcmp(propP2pSupported
, "1"));
48 if (c
>= '0' && c
<= '9')
50 if (c
>= 'a' && c
<= 'f')
52 if (c
>= 'A' && c
<= 'F')
58 hex2byte(const char* hex
)
70 // This function is equivalent to printf_decode() at src/utils/common.c in
74 convertToBytes(char* buf
, uint32_t maxlen
, const char* str
)
76 const char *pos
= str
;
134 if (*pos
>= '0' && *pos
<= '7')
135 val
= val
* 8 + (*pos
++ - '0');
136 if (*pos
>= '0' && *pos
<= '7')
137 val
= val
* 8 + (*pos
++ - '0');
152 // This is the same algorithm as in InflateUTF8StringToBuffer with Copy and
153 // while ignoring invalids.
154 // https://mxr.mozilla.org/mozilla-central/source/js/src/vm/CharacterEncoding.cpp#231
156 static const uint32_t REPLACE_UTF8
= 0xFFFD;
159 LossyConvertUTF8toUTF16(const char* aInput
, uint32_t aLength
, nsAString
& aOut
)
161 JS::UTF8Chars
src(aInput
, aLength
);
163 char16_t dst
[aLength
]; // Allocating for worst case.
165 // Count how many char16_t characters are needed in the inflated string.
166 // |i| is the index into |src|, and |j| is the the index into |dst|.
167 size_t srclen
= src
.length();
169 for (uint32_t i
= 0; i
< srclen
; i
++, j
++) {
170 uint32_t v
= uint32_t(src
[i
]);
171 if (v
== uint32_t('\0') && i
< srclen
- 1) {
172 // If the leading byte is '\0' and it's not the last byte,
173 // just ignore it to prevent from being truncated. This could
174 // be caused by |convertToBytes| (e.g. \x00 would be converted to '\0')
179 // ASCII code unit. Simple copy.
180 dst
[j
] = char16_t(v
);
182 // Non-ASCII code unit. Determine its length in bytes (n).
184 while (v
& (0x80 >> n
))
187 #define INVALID(report, arg, n2) \
190 goto invalidMultiByteCodeUnit; \
193 // Check the leading byte.
195 INVALID(ReportInvalidCharacter
, i
, 1);
197 // Check that |src| is large enough to hold an n-byte code unit.
199 INVALID(ReportBufferTooSmall
, /* dummy = */ 0, 1);
201 // Check the second byte. From Unicode Standard v6.2, Table 3-7
202 // Well-Formed UTF-8 Byte Sequences.
203 if ((v
== 0xE0 && ((uint8_t)src
[i
+ 1] & 0xE0) != 0xA0) || // E0 A0~BF
204 (v
== 0xED && ((uint8_t)src
[i
+ 1] & 0xE0) != 0x80) || // ED 80~9F
205 (v
== 0xF0 && ((uint8_t)src
[i
+ 1] & 0xF0) == 0x80) || // F0 90~BF
206 (v
== 0xF4 && ((uint8_t)src
[i
+ 1] & 0xF0) != 0x80)) // F4 80~8F
208 INVALID(ReportInvalidCharacter
, i
, 1);
211 // Check the continuation bytes.
212 for (uint32_t m
= 1; m
< n
; m
++)
213 if ((src
[i
+ m
] & 0xC0) != 0x80)
214 INVALID(ReportInvalidCharacter
, i
, m
);
216 // Determine the code unit's length in char16_t units and act accordingly.
217 v
= JS::Utf8ToOneUcs4Char((uint8_t *)&src
[i
], n
);
219 // The n-byte UTF8 code unit will fit in a single char16_t.
220 dst
[j
] = char16_t(v
);
224 // The n-byte UTF8 code unit will fit in two char16_t units.
225 dst
[j
] = char16_t((v
>> 10) + 0xD800);
227 dst
[j
] = char16_t((v
& 0x3FF) + 0xDC00);
229 // The n-byte UTF8 code unit won't fit in two char16_t units.
230 INVALID(ReportTooBigCharacter
, v
, 1);
234 invalidMultiByteCodeUnit
:
235 // Move i to the last byte of the multi-byte code unit; the loop
236 // header will do the final i++ to move to the start of the next
246 // Helper to check we have loaded the hardware shared library.
247 #define CHECK_HWLIB(ret) \
248 void* hwLib = GetSharedLibrary(); \
250 NS_WARNING("No /system/lib/libhardware_legacy.so"); \
254 #define DEFAULT_IMPL(name, ret, args...) \
255 DEFINE_DLFUNC(name, ret, args...) \
256 ret do_##name(args) { \
261 // ICS implementation.
262 class ICSWpaSupplicantImpl
: public WpaSupplicantImpl
265 DEFAULT_IMPL(wifi_load_driver
, int32_t, )
266 DEFAULT_IMPL(wifi_unload_driver
, int32_t, )
268 DEFINE_DLFUNC(wifi_wait_for_event
, int32_t, char*, size_t)
269 int32_t do_wifi_wait_for_event(const char *iface
, char *buf
, size_t len
) {
270 USE_DLFUNC(wifi_wait_for_event
)
271 return wifi_wait_for_event(buf
, len
);
274 DEFINE_DLFUNC(wifi_command
, int32_t, const char*, char*, size_t*)
275 int32_t do_wifi_command(const char* iface
, const char* cmd
, char* buf
, size_t* len
) {
276 USE_DLFUNC(wifi_command
)
277 return wifi_command(cmd
, buf
, len
);
280 DEFINE_DLFUNC(wifi_start_supplicant
, int32_t, )
281 int32_t do_wifi_start_supplicant(int32_t) {
282 USE_DLFUNC(wifi_start_supplicant
)
283 return wifi_start_supplicant();
286 DEFINE_DLFUNC(wifi_stop_supplicant
, int32_t)
287 int32_t do_wifi_stop_supplicant(int32_t) {
288 USE_DLFUNC(wifi_stop_supplicant
)
289 return wifi_stop_supplicant();
292 DEFINE_DLFUNC(wifi_connect_to_supplicant
, int32_t, )
293 int32_t do_wifi_connect_to_supplicant(const char* iface
) {
294 USE_DLFUNC(wifi_connect_to_supplicant
)
295 return wifi_connect_to_supplicant();
298 DEFINE_DLFUNC(wifi_close_supplicant_connection
, void, )
299 void do_wifi_close_supplicant_connection(const char* iface
) {
300 USE_DLFUNC(wifi_close_supplicant_connection
)
301 return wifi_close_supplicant_connection();
305 // JB implementation.
306 // We only redefine the methods that have a different signature than on ICS.
307 class JBWpaSupplicantImpl
: public ICSWpaSupplicantImpl
310 DEFINE_DLFUNC(wifi_wait_for_event
, int32_t, const char*, char*, size_t)
311 int32_t do_wifi_wait_for_event(const char* iface
, char* buf
, size_t len
) {
312 USE_DLFUNC(wifi_wait_for_event
)
313 return wifi_wait_for_event(iface
, buf
, len
);
316 DEFINE_DLFUNC(wifi_command
, int32_t, const char*, const char*, char*, size_t*)
317 int32_t do_wifi_command(const char* iface
, const char* cmd
, char* buf
, size_t* len
) {
318 USE_DLFUNC(wifi_command
)
319 return wifi_command(iface
, cmd
, buf
, len
);
322 DEFINE_DLFUNC(wifi_start_supplicant
, int32_t, int32_t)
323 int32_t do_wifi_start_supplicant(int32_t arg
) {
324 USE_DLFUNC(wifi_start_supplicant
)
325 return wifi_start_supplicant(arg
);
328 DEFINE_DLFUNC(wifi_stop_supplicant
, int32_t, int32_t)
329 int32_t do_wifi_stop_supplicant(int32_t arg
) {
330 USE_DLFUNC(wifi_stop_supplicant
)
331 return wifi_stop_supplicant(arg
);
334 DEFINE_DLFUNC(wifi_connect_to_supplicant
, int32_t, const char*)
335 int32_t do_wifi_connect_to_supplicant(const char* iface
) {
336 USE_DLFUNC(wifi_connect_to_supplicant
)
337 return wifi_connect_to_supplicant(iface
);
340 DEFINE_DLFUNC(wifi_close_supplicant_connection
, void, const char*)
341 void do_wifi_close_supplicant_connection(const char* iface
) {
342 USE_DLFUNC(wifi_close_supplicant_connection
)
343 wifi_close_supplicant_connection(iface
);
347 // KK implementation.
348 // We only redefine the methods that have a different signature than on ICS.
349 class KKWpaSupplicantImpl
: public ICSWpaSupplicantImpl
352 DEFINE_DLFUNC(wifi_start_supplicant
, int32_t, int32_t)
353 int32_t do_wifi_start_supplicant(int32_t arg
) {
354 USE_DLFUNC(wifi_start_supplicant
)
355 return wifi_start_supplicant(arg
);
358 DEFINE_DLFUNC(wifi_stop_supplicant
, int32_t, int32_t)
359 int32_t do_wifi_stop_supplicant(int32_t arg
) {
360 USE_DLFUNC(wifi_stop_supplicant
)
361 return wifi_stop_supplicant(arg
);
364 DEFINE_DLFUNC(wifi_command
, int32_t, const char*, char*, size_t*)
365 int32_t do_wifi_command(const char* iface
, const char* cmd
, char* buf
, size_t* len
) {
366 char command
[COMMAND_SIZE
];
367 if (!strcmp(iface
, "p2p0")) {
368 // Commands for p2p0 interface don't need prefix
369 PR_snprintf(command
, COMMAND_SIZE
, "%s", cmd
);
372 PR_snprintf(command
, COMMAND_SIZE
, "IFNAME=%s %s", iface
, cmd
);
374 USE_DLFUNC(wifi_command
)
375 return wifi_command(command
, buf
, len
);
379 // Concrete class to use to access the wpa supplicant.
380 WpaSupplicant::WpaSupplicant()
382 char propVersion
[PROPERTY_VALUE_MAX
];
383 property_get("ro.build.version.sdk", propVersion
, "0");
384 mSdkVersion
= strtol(propVersion
, nullptr, 10);
386 if (mSdkVersion
< 16) {
387 mImpl
= new ICSWpaSupplicantImpl();
388 } else if (mSdkVersion
< 19) {
389 mImpl
= new JBWpaSupplicantImpl();
391 mImpl
= new KKWpaSupplicantImpl();
393 mWifiHotspotUtils
= new WifiHotspotUtils();
396 void WpaSupplicant::WaitForEvent(nsAString
& aEvent
, const nsCString
& aInterface
)
400 char buffer
[BUFFER_SIZE
];
401 int32_t ret
= mImpl
->do_wifi_wait_for_event(aInterface
.get(), buffer
, BUFFER_SIZE
);
402 CheckBuffer(buffer
, ret
, aEvent
);
405 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
408 * Make a subnet mask.
410 uint32_t WpaSupplicant::MakeMask(uint32_t len
) {
412 for (uint32_t i
= 0; i
< len
; ++i
) {
413 mask
|= (0x80000000 >> i
);
418 bool WpaSupplicant::ExecuteCommand(CommandOptions aOptions
,
419 WifiResultOptions
& aResult
,
420 const nsCString
& aInterface
)
424 if (!mWifiHotspotUtils
->GetSharedLibrary()) {
428 // Always correlate the opaque ids.
429 aResult
.mId
= aOptions
.mId
;
431 if (aOptions
.mCmd
.EqualsLiteral("command")) {
432 size_t len
= BUFFER_SIZE
- 1;
433 char buffer
[BUFFER_SIZE
];
434 NS_ConvertUTF16toUTF8
request(aOptions
.mRequest
);
435 aResult
.mStatus
= mImpl
->do_wifi_command(aInterface
.get(), request
.get(), buffer
, &len
);
437 if (aResult
.mStatus
== 0) {
438 if (buffer
[len
- 1] == '\n') { // remove trailing new lines.
442 CheckBuffer(buffer
, len
, value
);
444 aResult
.mReply
= value
;
445 } else if (aOptions
.mCmd
.EqualsLiteral("close_supplicant_connection")) {
446 mImpl
->do_wifi_close_supplicant_connection(aInterface
.get());
447 } else if (aOptions
.mCmd
.EqualsLiteral("load_driver")) {
448 aResult
.mStatus
= mImpl
->do_wifi_load_driver();
449 } else if (aOptions
.mCmd
.EqualsLiteral("unload_driver")) {
450 aResult
.mStatus
= mImpl
->do_wifi_unload_driver();
451 } else if (aOptions
.mCmd
.EqualsLiteral("start_supplicant")) {
452 aResult
.mStatus
= mImpl
->do_wifi_start_supplicant(GetWifiP2pSupported() ? 1 : 0);
453 } else if (aOptions
.mCmd
.EqualsLiteral("stop_supplicant")) {
454 aResult
.mStatus
= mImpl
->do_wifi_stop_supplicant(0);
455 } else if (aOptions
.mCmd
.EqualsLiteral("connect_to_supplicant")) {
456 aResult
.mStatus
= mImpl
->do_wifi_connect_to_supplicant(aInterface
.get());
457 } else if (aOptions
.mCmd
.EqualsLiteral("hostapd_command")) {
458 size_t len
= BUFFER_SIZE
- 1;
459 char buffer
[BUFFER_SIZE
];
460 NS_ConvertUTF16toUTF8
request(aOptions
.mRequest
);
461 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_hostapd_command(request
.get(),
465 if (aResult
.mStatus
== 0) {
466 if (buffer
[len
- 1] == '\n') { // remove trailing new lines.
470 CheckBuffer(buffer
, len
, value
);
472 aResult
.mReply
= value
;
473 } else if (aOptions
.mCmd
.EqualsLiteral("hostapd_get_stations")) {
474 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_hostapd_get_stations();
475 } else if (aOptions
.mCmd
.EqualsLiteral("connect_to_hostapd")) {
476 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_connect_to_hostapd();
477 } else if (aOptions
.mCmd
.EqualsLiteral("close_hostapd_connection")) {
478 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_close_hostapd_connection();
479 } else if (aOptions
.mCmd
.EqualsLiteral("hostapd_command")) {
480 size_t len
= BUFFER_SIZE
- 1;
481 char buffer
[BUFFER_SIZE
];
482 NS_ConvertUTF16toUTF8
request(aOptions
.mRequest
);
483 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_hostapd_command(request
.get(),
487 if (aResult
.mStatus
== 0) {
488 if (buffer
[len
- 1] == '\n') { // remove trailing new lines.
492 CheckBuffer(buffer
, len
, value
);
494 aResult
.mReply
= value
;
495 } else if (aOptions
.mCmd
.EqualsLiteral("hostapd_get_stations")) {
496 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_hostapd_get_stations();
497 } else if (aOptions
.mCmd
.EqualsLiteral("connect_to_hostapd")) {
498 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_connect_to_hostapd();
499 } else if (aOptions
.mCmd
.EqualsLiteral("close_hostapd_connection")) {
500 aResult
.mStatus
= mWifiHotspotUtils
->do_wifi_close_hostapd_connection();
503 NS_WARNING("WpaSupplicant::ExecuteCommand : Unknown command");
504 printf_stderr("WpaSupplicant::ExecuteCommand : Unknown command: %s",
505 NS_ConvertUTF16toUTF8(aOptions
.mCmd
).get());
512 // Checks the buffer and do the utf processing.
514 WpaSupplicant::CheckBuffer(char* buffer
, int32_t length
,
517 if (length
<= 0 || length
>= (BUFFER_SIZE
- 1)) {
518 NS_WARNING("WpaSupplicant::CheckBuffer: Invalid buffer length");
522 if (mSdkVersion
< 18) {
524 LossyConvertUTF8toUTF16(buffer
, length
, aEvent
);
528 // After Android JB4.3, the SSIDs have been converted into printable form.
529 // In most of cases, SSIDs do not use unprintable characters, but IEEE 802.11
530 // standard does not limit the used character set, so anything could be used
531 // in an SSID. Convert it to raw data form here.
532 char bytesBuffer
[BUFFER_SIZE
];
533 uint32_t bytes
= convertToBytes(bytesBuffer
, length
, buffer
);
534 if (bytes
<= 0 || bytes
>= BUFFER_SIZE
) {
535 NS_WARNING("WpaSupplicant::CheckBuffer: Invalid bytesbuffer length");
538 bytesBuffer
[bytes
] = 0;
539 LossyConvertUTF8toUTF16(bytesBuffer
, bytes
, aEvent
);