blob: bed66d92611751374efb079bcca86a577a4f528a [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.wifi;
17
18import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
19import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
20import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
21import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
22
23import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQP3GPPNetwork;
24import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPDomName;
25import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPIPAddrAvailability;
26import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPNAIRealm;
27import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPRoamingConsortium;
28import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPVenueName;
29import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSConnCapability;
30import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSFriendlyName;
31import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSOSUProviders;
32import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSWANMetrics;
33
34import android.annotation.NonNull;
35import android.content.Context;
36import android.hardware.wifi.supplicant.V1_0.ISupplicant;
37import android.hardware.wifi.supplicant.V1_0.ISupplicantIface;
38import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork;
39import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface;
40import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
41import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork;
42import android.hardware.wifi.supplicant.V1_0.IfaceType;
43import android.hardware.wifi.supplicant.V1_0.SupplicantStatus;
44import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode;
45import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods;
46import android.hardware.wifi.supplicant.V1_2.DppAkm;
47import android.hardware.wifi.supplicant.V1_2.DppFailureCode;
48import android.hidl.manager.V1_0.IServiceManager;
49import android.hidl.manager.V1_0.IServiceNotification;
50import android.net.IpConfiguration;
51import android.net.wifi.SupplicantState;
52import android.net.wifi.WifiConfiguration;
53import android.net.wifi.WifiManager;
54import android.net.wifi.WifiSsid;
55import android.os.Handler;
56import android.os.HidlSupport.Mutable;
57import android.os.HwRemoteBinder;
58import android.os.Looper;
59import android.os.Process;
60import android.os.RemoteException;
61import android.text.TextUtils;
62import android.util.Log;
63import android.util.MutableBoolean;
64import android.util.MutableInt;
65import android.util.Pair;
66import android.util.SparseArray;
67
68import com.android.internal.annotations.VisibleForTesting;
69import com.android.server.wifi.WifiNative.DppEventCallback;
70import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler;
71import com.android.server.wifi.hotspot2.AnqpEvent;
72import com.android.server.wifi.hotspot2.IconEvent;
73import com.android.server.wifi.hotspot2.WnmData;
74import com.android.server.wifi.hotspot2.anqp.ANQPElement;
75import com.android.server.wifi.hotspot2.anqp.ANQPParser;
76import com.android.server.wifi.hotspot2.anqp.Constants;
77import com.android.server.wifi.util.NativeUtil;
78
79import java.io.IOException;
80import java.nio.BufferUnderflowException;
81import java.nio.ByteBuffer;
82import java.nio.ByteOrder;
83import java.util.ArrayList;
84import java.util.HashMap;
85import java.util.List;
86import java.util.Map;
87import java.util.NoSuchElementException;
88import java.util.Objects;
89import java.util.regex.Matcher;
90import java.util.regex.Pattern;
91
92import javax.annotation.concurrent.ThreadSafe;
93
94/**
95 * Hal calls for bring up/shut down of the supplicant daemon and for
96 * sending requests to the supplicant daemon
97 * To maintain thread-safety, the locking protocol is that every non-static method (regardless of
98 * access level) acquires mLock.
99 */
100@ThreadSafe
101public class SupplicantStaIfaceHal {
102 private static final String TAG = "SupplicantStaIfaceHal";
103 @VisibleForTesting
104 public static final String HAL_INSTANCE_NAME = "default";
105 @VisibleForTesting
106 public static final String INIT_START_PROPERTY = "ctl.start";
107 @VisibleForTesting
108 public static final String INIT_STOP_PROPERTY = "ctl.stop";
109 @VisibleForTesting
110 public static final String INIT_SERVICE_NAME = "wpa_supplicant";
111 /**
112 * Regex pattern for extracting the wps device type bytes.
113 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
114 */
115 private static final Pattern WPS_DEVICE_TYPE_PATTERN =
116 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
117
118 private final Object mLock = new Object();
119 private boolean mVerboseLoggingEnabled = false;
120
121 // Supplicant HAL interface objects
122 private IServiceManager mIServiceManager = null;
123 private ISupplicant mISupplicant;
124 private HashMap<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>();
125 private HashMap<String, ISupplicantStaIfaceCallback> mISupplicantStaIfaceCallbacks =
126 new HashMap<>();
127 private HashMap<String, SupplicantStaNetworkHal> mCurrentNetworkRemoteHandles = new HashMap<>();
128 private HashMap<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
129 private SupplicantDeathEventHandler mDeathEventHandler;
130 private ServiceManagerDeathRecipient mServiceManagerDeathRecipient;
131 private SupplicantDeathRecipient mSupplicantDeathRecipient;
132 // Death recipient cookie registered for current supplicant instance.
133 private long mDeathRecipientCookie = 0;
134 private final Context mContext;
135 private final WifiMonitor mWifiMonitor;
136 private final PropertyService mPropertyService;
137 private final Handler mEventHandler;
138 private DppEventCallback mDppCallback = null;
139
140 private final IServiceNotification mServiceNotificationCallback =
141 new IServiceNotification.Stub() {
142 public void onRegistration(String fqName, String name, boolean preexisting) {
143 synchronized (mLock) {
144 if (mVerboseLoggingEnabled) {
145 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
146 + ", " + name + " preexisting=" + preexisting);
147 }
148 if (!initSupplicantService()) {
149 Log.e(TAG, "initalizing ISupplicant failed.");
150 supplicantServiceDiedHandler(mDeathRecipientCookie);
151 } else {
152 Log.i(TAG, "Completed initialization of ISupplicant.");
153 }
154 }
155 }
156 };
157 private class ServiceManagerDeathRecipient implements HwRemoteBinder.DeathRecipient {
158 @Override
159 public void serviceDied(long cookie) {
160 mEventHandler.post(() -> {
161 synchronized (mLock) {
162 Log.w(TAG, "IServiceManager died: cookie=" + cookie);
163 supplicantServiceDiedHandler(mDeathRecipientCookie);
164 mIServiceManager = null; // Will need to register a new ServiceNotification
165 }
166 });
167 }
168 }
169 private class SupplicantDeathRecipient implements HwRemoteBinder.DeathRecipient {
170 @Override
171 public void serviceDied(long cookie) {
172 mEventHandler.post(() -> {
173 synchronized (mLock) {
174 Log.w(TAG, "ISupplicant died: cookie=" + cookie);
175 supplicantServiceDiedHandler(cookie);
176 }
177 });
178 }
179 }
180
181 public SupplicantStaIfaceHal(Context context, WifiMonitor monitor,
182 PropertyService propertyService, Looper looper) {
183 mContext = context;
184 mWifiMonitor = monitor;
185 mPropertyService = propertyService;
186 mEventHandler = new Handler(looper);
187
188 mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient();
189 mSupplicantDeathRecipient = new SupplicantDeathRecipient();
190 }
191
192 /**
193 * Enable/Disable verbose logging.
194 *
195 * @param enable true to enable, false to disable.
196 */
197 void enableVerboseLogging(boolean enable) {
198 synchronized (mLock) {
199 mVerboseLoggingEnabled = enable;
200 }
201 }
202
203 private boolean linkToServiceManagerDeath() {
204 synchronized (mLock) {
205 if (mIServiceManager == null) return false;
206 try {
207 if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) {
208 Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
209 supplicantServiceDiedHandler(mDeathRecipientCookie);
210 mIServiceManager = null; // Will need to register a new ServiceNotification
211 return false;
212 }
213 } catch (RemoteException e) {
214 Log.e(TAG, "IServiceManager.linkToDeath exception", e);
215 return false;
216 }
217 return true;
218 }
219 }
220
221 /**
222 * Registers a service notification for the ISupplicant service, which triggers initialization
223 * of the ISupplicantStaIface
224 * @return true if the service notification was successfully registered
225 */
226 public boolean initialize() {
227 synchronized (mLock) {
228 if (mVerboseLoggingEnabled) {
229 Log.i(TAG, "Registering ISupplicant service ready callback.");
230 }
231 mISupplicant = null;
232 mISupplicantStaIfaces.clear();
233 if (mIServiceManager != null) {
234 // Already have an IServiceManager and serviceNotification registered, don't
235 // don't register another.
236 return true;
237 }
238 try {
239 mIServiceManager = getServiceManagerMockable();
240 if (mIServiceManager == null) {
241 Log.e(TAG, "Failed to get HIDL Service Manager");
242 return false;
243 }
244 if (!linkToServiceManagerDeath()) {
245 return false;
246 }
247 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it
248 exists */
249 if (!mIServiceManager.registerForNotifications(
250 ISupplicant.kInterfaceName, "", mServiceNotificationCallback)) {
251 Log.e(TAG, "Failed to register for notifications to "
252 + ISupplicant.kInterfaceName);
253 mIServiceManager = null; // Will need to register a new ServiceNotification
254 return false;
255 }
256 } catch (RemoteException e) {
257 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: "
258 + e);
259 supplicantServiceDiedHandler(mDeathRecipientCookie);
260 }
261 return true;
262 }
263 }
264
265 private boolean linkToSupplicantDeath() {
266 synchronized (mLock) {
267 if (mISupplicant == null) return false;
268 try {
269 if (!mISupplicant.linkToDeath(mSupplicantDeathRecipient, ++mDeathRecipientCookie)) {
270 Log.wtf(TAG, "Error on linkToDeath on ISupplicant");
271 supplicantServiceDiedHandler(mDeathRecipientCookie);
272 return false;
273 }
274 } catch (RemoteException e) {
275 Log.e(TAG, "ISupplicant.linkToDeath exception", e);
276 return false;
277 }
278 return true;
279 }
280 }
281
282 private boolean initSupplicantService() {
283 synchronized (mLock) {
284 try {
285 mISupplicant = getSupplicantMockable();
286 } catch (RemoteException e) {
287 Log.e(TAG, "ISupplicant.getService exception: " + e);
288 return false;
289 } catch (NoSuchElementException e) {
290 Log.e(TAG, "ISupplicant.getService exception: " + e);
291 return false;
292 }
293 if (mISupplicant == null) {
294 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup");
295 return false;
296 }
297 if (!linkToSupplicantDeath()) {
298 return false;
299 }
300 }
301 return true;
302 }
303
304 private int getCurrentNetworkId(@NonNull String ifaceName) {
305 synchronized (mLock) {
306 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
307 if (currentConfig == null) {
308 return WifiConfiguration.INVALID_NETWORK_ID;
309 }
310 return currentConfig.networkId;
311 }
312 }
313
314 /**
315 * Setup a STA interface for the specified iface name.
316 *
317 * @param ifaceName Name of the interface.
318 * @return true on success, false otherwise.
319 */
320 public boolean setupIface(@NonNull String ifaceName) {
321 final String methodStr = "setupIface";
322 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) != null) return false;
323 ISupplicantIface ifaceHwBinder;
324
325 if (isV1_1()) {
326 ifaceHwBinder = addIfaceV1_1(ifaceName);
327 } else {
328 ifaceHwBinder = getIfaceV1_0(ifaceName);
329 }
330 if (ifaceHwBinder == null) {
331 Log.e(TAG, "setupIface got null iface");
332 return false;
333 }
334 SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
335
336 if (isV1_2()) {
337 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface =
338 getStaIfaceMockableV1_2(ifaceHwBinder);
339
340 SupplicantStaIfaceHalCallbackV1_1 callbackV11 =
341 new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback);
342
343 SupplicantStaIfaceHalCallbackV1_2 callbackV12 =
344 new SupplicantStaIfaceHalCallbackV1_2(callbackV11);
345
346 if (!registerCallbackV1_2(iface, callbackV12)) {
347 return false;
348 }
349 mISupplicantStaIfaces.put(ifaceName, iface);
350 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV11);
351 } else if (isV1_1()) {
352 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface =
353 getStaIfaceMockableV1_1(ifaceHwBinder);
354 SupplicantStaIfaceHalCallbackV1_1 callbackV1_1 =
355 new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback);
356
357 if (!registerCallbackV1_1(iface, callbackV1_1)) {
358 return false;
359 }
360 mISupplicantStaIfaces.put(ifaceName, iface);
361 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV1_1);
362 } else {
363 ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
364
365 if (!registerCallback(iface, callback)) {
366 return false;
367 }
368 mISupplicantStaIfaces.put(ifaceName, iface);
369 mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
370 }
371 return true;
372 }
373
374 /**
375 * Get a STA interface for the specified iface name.
376 *
377 * @param ifaceName Name of the interface.
378 * @return true on success, false otherwise.
379 */
380 private ISupplicantIface getIfaceV1_0(@NonNull String ifaceName) {
381 synchronized (mLock) {
382 if (mISupplicant == null) {
383 return null;
384 }
385
386 /** List all supplicant Ifaces */
387 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
388 try {
389 mISupplicant.listInterfaces((SupplicantStatus status,
390 ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
391 if (status.code != SupplicantStatusCode.SUCCESS) {
392 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
393 return;
394 }
395 supplicantIfaces.addAll(ifaces);
396 });
397 } catch (RemoteException e) {
398 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
399 handleRemoteException(e, "listInterfaces");
400 return null;
401 }
402 if (supplicantIfaces.size() == 0) {
403 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
404 return null;
405 }
406 Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
407 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
408 if (ifaceInfo.type == IfaceType.STA && ifaceName.equals(ifaceInfo.name)) {
409 try {
410 mISupplicant.getInterface(ifaceInfo,
411 (SupplicantStatus status, ISupplicantIface iface) -> {
412 if (status.code != SupplicantStatusCode.SUCCESS) {
413 Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
414 return;
415 }
416 supplicantIface.value = iface;
417 });
418 } catch (RemoteException e) {
419 Log.e(TAG, "ISupplicant.getInterface exception: " + e);
420 handleRemoteException(e, "getInterface");
421 return null;
422 }
423 break;
424 }
425 }
426 return supplicantIface.value;
427 }
428 }
429
430 /**
431 * Create a STA interface for the specified iface name.
432 *
433 * @param ifaceName Name of the interface.
434 * @return true on success, false otherwise.
435 */
436 private ISupplicantIface addIfaceV1_1(@NonNull String ifaceName) {
437 synchronized (mLock) {
438 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
439 ifaceInfo.name = ifaceName;
440 ifaceInfo.type = IfaceType.STA;
441 Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
442 try {
443 getSupplicantMockableV1_1().addInterface(ifaceInfo,
444 (SupplicantStatus status, ISupplicantIface iface) -> {
445 if (status.code != SupplicantStatusCode.SUCCESS
446 && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) {
447 Log.e(TAG, "Failed to create ISupplicantIface " + status.code);
448 return;
449 }
450 supplicantIface.value = iface;
451 });
452 } catch (RemoteException e) {
453 Log.e(TAG, "ISupplicant.addInterface exception: " + e);
454 handleRemoteException(e, "addInterface");
455 return null;
456 } catch (NoSuchElementException e) {
457 Log.e(TAG, "ISupplicant.addInterface exception: " + e);
458 handleNoSuchElementException(e, "addInterface");
459 return null;
460 }
461 return supplicantIface.value;
462 }
463 }
464
465 /**
466 * Teardown a STA interface for the specified iface name.
467 *
468 * @param ifaceName Name of the interface.
469 * @return true on success, false otherwise.
470 */
471 public boolean teardownIface(@NonNull String ifaceName) {
472 synchronized (mLock) {
473 final String methodStr = "teardownIface";
474 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) == null) return false;
475 if (isV1_1()) {
476 if (!removeIfaceV1_1(ifaceName)) {
477 Log.e(TAG, "Failed to remove iface = " + ifaceName);
478 return false;
479 }
480 }
481 if (mISupplicantStaIfaces.remove(ifaceName) == null) {
482 Log.e(TAG, "Trying to teardown unknown inteface");
483 return false;
484 }
485 mISupplicantStaIfaceCallbacks.remove(ifaceName);
486 return true;
487 }
488 }
489
490 /**
491 * Remove a STA interface for the specified iface name.
492 *
493 * @param ifaceName Name of the interface.
494 * @return true on success, false otherwise.
495 */
496 private boolean removeIfaceV1_1(@NonNull String ifaceName) {
497 synchronized (mLock) {
498 try {
499 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
500 ifaceInfo.name = ifaceName;
501 ifaceInfo.type = IfaceType.STA;
502 SupplicantStatus status = getSupplicantMockableV1_1().removeInterface(ifaceInfo);
503 if (status.code != SupplicantStatusCode.SUCCESS) {
504 Log.e(TAG, "Failed to remove iface " + status.code);
505 return false;
506 }
507 } catch (RemoteException e) {
508 Log.e(TAG, "ISupplicant.removeInterface exception: " + e);
509 handleRemoteException(e, "removeInterface");
510 return false;
511 } catch (NoSuchElementException e) {
512 Log.e(TAG, "ISupplicant.removeInterface exception: " + e);
513 handleNoSuchElementException(e, "removeInterface");
514 return false;
515 }
516 return true;
517 }
518 }
519
520 /**
521 * Registers a death notification for supplicant.
522 * @return Returns true on success.
523 */
524 public boolean registerDeathHandler(@NonNull SupplicantDeathEventHandler handler) {
525 if (mDeathEventHandler != null) {
526 Log.e(TAG, "Death handler already present");
527 }
528 mDeathEventHandler = handler;
529 return true;
530 }
531
532 /**
533 * Deregisters a death notification for supplicant.
534 * @return Returns true on success.
535 */
536 public boolean deregisterDeathHandler() {
537 if (mDeathEventHandler == null) {
538 Log.e(TAG, "No Death handler present");
539 }
540 mDeathEventHandler = null;
541 return true;
542 }
543
544
545 private void clearState() {
546 synchronized (mLock) {
547 mISupplicant = null;
548 mISupplicantStaIfaces.clear();
549 mCurrentNetworkLocalConfigs.clear();
550 mCurrentNetworkRemoteHandles.clear();
551 }
552 }
553
554 private void supplicantServiceDiedHandler(long cookie) {
555 synchronized (mLock) {
556 if (mDeathRecipientCookie != cookie) {
557 Log.i(TAG, "Ignoring stale death recipient notification");
558 return;
559 }
560 for (String ifaceName : mISupplicantStaIfaces.keySet()) {
561 mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName);
562 }
563 clearState();
564 if (mDeathEventHandler != null) {
565 mDeathEventHandler.onDeath();
566 }
567 }
568 }
569
570 /**
571 * Signals whether Initialization completed successfully.
572 */
573 public boolean isInitializationStarted() {
574 synchronized (mLock) {
575 return mIServiceManager != null;
576 }
577 }
578
579 /**
580 * Signals whether Initialization completed successfully.
581 */
582 public boolean isInitializationComplete() {
583 synchronized (mLock) {
584 return mISupplicant != null;
585 }
586 }
587
588
589 /**
590 * Start the supplicant daemon for V1_1 service.
591 *
592 * @return true on success, false otherwise.
593 */
594 private boolean startDaemon_V1_1() {
595 synchronized (mLock) {
596 try {
597 // This should startup supplicant daemon using the lazy start HAL mechanism.
598 getSupplicantMockableV1_1();
599 } catch (RemoteException e) {
600 Log.e(TAG, "Exception while trying to start supplicant: "
601 + e);
602 supplicantServiceDiedHandler(mDeathRecipientCookie);
603 return false;
604 } catch (NoSuchElementException e) {
605 // We're starting the daemon, so expect |NoSuchElementException|.
606 Log.d(TAG, "Successfully triggered start of supplicant using HIDL");
607 }
608 return true;
609 }
610 }
611
612 /**
613 * Start the supplicant daemon.
614 *
615 * @return true on success, false otherwise.
616 */
617 public boolean startDaemon() {
618 synchronized (mLock) {
619 if (isV1_1()) {
620 Log.i(TAG, "Starting supplicant using HIDL");
621 return startDaemon_V1_1();
622 } else {
623 Log.i(TAG, "Starting supplicant using init");
624 mPropertyService.set(INIT_START_PROPERTY, INIT_SERVICE_NAME);
625 return true;
626 }
627 }
628 }
629
630 /**
631 * Terminate the supplicant daemon for V1_1 service.
632 */
633 private void terminate_V1_1() {
634 synchronized (mLock) {
635 final String methodStr = "terminate";
636 if (!checkSupplicantAndLogFailure(methodStr)) return;
637 try {
638 getSupplicantMockableV1_1().terminate();
639 } catch (RemoteException e) {
640 handleRemoteException(e, methodStr);
641 } catch (NoSuchElementException e) {
642 handleNoSuchElementException(e, methodStr);
643 }
644 }
645 }
646
647 /**
648 * Terminate the supplicant daemon.
649 */
650 public void terminate() {
651 synchronized (mLock) {
652 if (isV1_1()) {
653 Log.i(TAG, "Terminating supplicant using HIDL");
654 terminate_V1_1();
655 } else {
656 Log.i(TAG, "Terminating supplicant using init");
657 mPropertyService.set(INIT_STOP_PROPERTY, INIT_SERVICE_NAME);
658 }
659 }
660 }
661
662 /**
663 * Wrapper functions to access static HAL methods, created to be mockable in unit tests
664 */
665 protected IServiceManager getServiceManagerMockable() throws RemoteException {
666 synchronized (mLock) {
667 return IServiceManager.getService();
668 }
669 }
670
671 protected ISupplicant getSupplicantMockable() throws RemoteException, NoSuchElementException {
672 synchronized (mLock) {
673 return ISupplicant.getService();
674 }
675 }
676
677 protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
678 throws RemoteException, NoSuchElementException {
679 synchronized (mLock) {
680 return android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom(
681 ISupplicant.getService());
682 }
683 }
684
685 protected android.hardware.wifi.supplicant.V1_2.ISupplicant getSupplicantMockableV1_2()
686 throws RemoteException, NoSuchElementException {
687 synchronized (mLock) {
688 return android.hardware.wifi.supplicant.V1_2.ISupplicant.castFrom(
689 ISupplicant.getService());
690 }
691 }
692
693 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
694 synchronized (mLock) {
695 return ISupplicantStaIface.asInterface(iface.asBinder());
696 }
697 }
698
699 protected android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface
700 getStaIfaceMockableV1_1(ISupplicantIface iface) {
701 synchronized (mLock) {
702 return android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface
703 .asInterface(iface.asBinder());
704 }
705 }
706
707 protected android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface
708 getStaIfaceMockableV1_2(ISupplicantIface iface) {
709 synchronized (mLock) {
710 return android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface
711 .asInterface(iface.asBinder());
712 }
713 }
714
715 /**
716 * Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for
717 * the device.
718 * @return true if supported, false otherwise.
719 */
720 private boolean isV1_1() {
721 return checkHalVersionByInterfaceName(
722 android.hardware.wifi.supplicant.V1_1.ISupplicant.kInterfaceName);
723 }
724
725 /**
726 * Uses the IServiceManager to check if the device is running V1_2 of the HAL from the VINTF for
727 * the device.
728 * @return true if supported, false otherwise.
729 */
730 private boolean isV1_2() {
731 return checkHalVersionByInterfaceName(
732 android.hardware.wifi.supplicant.V1_2.ISupplicant.kInterfaceName);
733 }
734
735 private boolean checkHalVersionByInterfaceName(String interfaceName) {
736 if (interfaceName == null) {
737 return false;
738 }
739 synchronized (mLock) {
740 if (mIServiceManager == null) {
741 Log.e(TAG, "checkHalVersionByInterfaceName: called but mServiceManager is null");
742 return false;
743 }
744 try {
745 return (mIServiceManager.getTransport(
746 interfaceName,
747 HAL_INSTANCE_NAME)
748 != IServiceManager.Transport.EMPTY);
749 } catch (RemoteException e) {
750 Log.e(TAG, "Exception while operating on IServiceManager: " + e);
751 handleRemoteException(e, "getTransport");
752 return false;
753 }
754 }
755 }
756
757 /**
758 * Helper method to look up the network object for the specified iface.
759 */
760 private ISupplicantStaIface getStaIface(@NonNull String ifaceName) {
761 return mISupplicantStaIfaces.get(ifaceName);
762 }
763
764 /**
765 * Helper method to look up the network object for the specified iface.
766 */
767 private SupplicantStaNetworkHal getCurrentNetworkRemoteHandle(@NonNull String ifaceName) {
768 return mCurrentNetworkRemoteHandles.get(ifaceName);
769 }
770
771 /**
772 * Helper method to look up the network config or the specified iface.
773 */
774 private WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) {
775 return mCurrentNetworkLocalConfigs.get(ifaceName);
776 }
777
778 /**
779 * Add a network configuration to wpa_supplicant.
780 *
781 * @param config Config corresponding to the network.
782 * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
783 * for the current network.
784 */
785 private Pair<SupplicantStaNetworkHal, WifiConfiguration>
786 addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
787 synchronized (mLock) {
788 logi("addSupplicantStaNetwork via HIDL");
789 if (config == null) {
790 loge("Cannot add NULL network!");
791 return null;
792 }
793 SupplicantStaNetworkHal network = addNetwork(ifaceName);
794 if (network == null) {
795 loge("Failed to add a network!");
796 return null;
797 }
798 boolean saveSuccess = false;
799 try {
800 saveSuccess = network.saveWifiConfiguration(config);
801 } catch (IllegalArgumentException e) {
802 Log.e(TAG, "Exception while saving config params: " + config, e);
803 }
804 if (!saveSuccess) {
805 loge("Failed to save variables for: " + config.configKey());
806 if (!removeAllNetworks(ifaceName)) {
807 loge("Failed to remove all networks on failure.");
808 }
809 return null;
810 }
811 return new Pair(network, new WifiConfiguration(config));
812 }
813 }
814
815 /**
816 * Add the provided network configuration to wpa_supplicant and initiate connection to it.
817 * This method does the following:
818 * 1. If |config| is different to the current supplicant network, removes all supplicant
819 * networks and saves |config|.
820 * 2. Select the new network in wpa_supplicant.
821 *
822 * @param ifaceName Name of the interface.
823 * @param config WifiConfiguration parameters for the provided network.
824 * @return {@code true} if it succeeds, {@code false} otherwise
825 */
826 public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
827 synchronized (mLock) {
828 logd("connectToNetwork " + config.configKey());
829 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
830 if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
831 String networkSelectionBSSID = config.getNetworkSelectionStatus()
832 .getNetworkSelectionBSSID();
833 String networkSelectionBSSIDCurrent =
834 currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
835 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
836 logd("Network is already saved, will not trigger remove and add operation.");
837 } else {
838 logd("Network is already saved, but need to update BSSID.");
839 if (!setCurrentNetworkBssid(
840 ifaceName,
841 config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
842 loge("Failed to set current network BSSID.");
843 return false;
844 }
845 mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
846 }
847 } else {
848 mCurrentNetworkRemoteHandles.remove(ifaceName);
849 mCurrentNetworkLocalConfigs.remove(ifaceName);
850 if (!removeAllNetworks(ifaceName)) {
851 loge("Failed to remove existing networks");
852 return false;
853 }
854 Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
855 addNetworkAndSaveConfig(ifaceName, config);
856 if (pair == null) {
857 loge("Failed to add/save network configuration: " + config.configKey());
858 return false;
859 }
860 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
861 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
862 }
863 SupplicantStaNetworkHal networkHandle =
864 checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
865 if (networkHandle == null || !networkHandle.select()) {
866 loge("Failed to select network configuration: " + config.configKey());
867 return false;
868 }
869 return true;
870 }
871 }
872
873 /**
874 * Initiates roaming to the already configured network in wpa_supplicant. If the network
875 * configuration provided does not match the already configured network, then this triggers
876 * a new connection attempt (instead of roam).
877 * 1. First check if we're attempting to connect to the same network as we currently have
878 * configured.
879 * 2. Set the new bssid for the network in wpa_supplicant.
880 * 3. Trigger reassociate command to wpa_supplicant.
881 *
882 * @param ifaceName Name of the interface.
883 * @param config WifiConfiguration parameters for the provided network.
884 * @return {@code true} if it succeeds, {@code false} otherwise
885 */
886 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) {
887 synchronized (mLock) {
888 if (getCurrentNetworkId(ifaceName) != config.networkId) {
889 Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
890 + "Current network ID: " + getCurrentNetworkId(ifaceName));
891 return connectToNetwork(ifaceName, config);
892 }
893 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
894 logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")");
895
896 SupplicantStaNetworkHal networkHandle =
897 checkSupplicantStaNetworkAndLogFailure(ifaceName, "roamToNetwork");
898 if (networkHandle == null || !networkHandle.setBssid(bssid)) {
899 loge("Failed to set new bssid on network: " + config.configKey());
900 return false;
901 }
902 if (!reassociate(ifaceName)) {
903 loge("Failed to trigger reassociate");
904 return false;
905 }
906 return true;
907 }
908 }
909
910 /**
911 * Load all the configured networks from wpa_supplicant.
912 *
913 * @param ifaceName Name of the interface.
914 * @param configs Map of configuration key to configuration objects corresponding to all
915 * the networks.
916 * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
917 * @return true if succeeds, false otherwise.
918 */
919 public boolean loadNetworks(@NonNull String ifaceName, Map<String, WifiConfiguration> configs,
920 SparseArray<Map<String, String>> networkExtras) {
921 synchronized (mLock) {
922 List<Integer> networkIds = listNetworks(ifaceName);
923 if (networkIds == null) {
924 Log.e(TAG, "Failed to list networks");
925 return false;
926 }
927 for (Integer networkId : networkIds) {
928 SupplicantStaNetworkHal network = getNetwork(ifaceName, networkId);
929 if (network == null) {
930 Log.e(TAG, "Failed to get network with ID: " + networkId);
931 return false;
932 }
933 WifiConfiguration config = new WifiConfiguration();
934 Map<String, String> networkExtra = new HashMap<>();
935 boolean loadSuccess = false;
936 try {
937 loadSuccess = network.loadWifiConfiguration(config, networkExtra);
938 } catch (IllegalArgumentException e) {
939 Log.wtf(TAG, "Exception while loading config params: " + config, e);
940 }
941 if (!loadSuccess) {
942 Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId
943 + ". Skipping...");
944 continue;
945 }
946 // Set the default IP assignments.
947 config.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
948 config.setProxySettings(IpConfiguration.ProxySettings.NONE);
949
950 networkExtras.put(networkId, networkExtra);
951 String configKey =
952 networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY);
953 final WifiConfiguration duplicateConfig = configs.put(configKey, config);
954 if (duplicateConfig != null) {
955 // The network is already known. Overwrite the duplicate entry.
956 Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId);
957 removeNetwork(ifaceName, duplicateConfig.networkId);
958 networkExtras.remove(duplicateConfig.networkId);
959 }
960 }
961 return true;
962 }
963 }
964
965 /**
966 * Remove the request |networkId| from supplicant if it's the current network,
967 * if the current configured network matches |networkId|.
968 *
969 * @param ifaceName Name of the interface.
970 * @param networkId network id of the network to be removed from supplicant.
971 */
972 public void removeNetworkIfCurrent(@NonNull String ifaceName, int networkId) {
973 synchronized (mLock) {
974 if (getCurrentNetworkId(ifaceName) == networkId) {
975 // Currently we only save 1 network in supplicant.
976 removeAllNetworks(ifaceName);
977 }
978 }
979 }
980
981 /**
982 * Remove all networks from supplicant
983 *
984 * @param ifaceName Name of the interface.
985 */
986 public boolean removeAllNetworks(@NonNull String ifaceName) {
987 synchronized (mLock) {
988 ArrayList<Integer> networks = listNetworks(ifaceName);
989 if (networks == null) {
990 Log.e(TAG, "removeAllNetworks failed, got null networks");
991 return false;
992 }
993 for (int id : networks) {
994 if (!removeNetwork(ifaceName, id)) {
995 Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
996 return false;
997 }
998 }
999 // Reset current network info. Probably not needed once we add support to remove/reset
1000 // current network on receiving disconnection event from supplicant (b/32898136).
1001 mCurrentNetworkRemoteHandles.remove(ifaceName);
1002 mCurrentNetworkLocalConfigs.remove(ifaceName);
1003 return true;
1004 }
1005 }
1006
1007 /**
1008 * Set the currently configured network's bssid.
1009 *
1010 * @param ifaceName Name of the interface.
1011 * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
1012 * @return true if succeeds, false otherwise.
1013 */
1014 public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) {
1015 synchronized (mLock) {
1016 SupplicantStaNetworkHal networkHandle =
1017 checkSupplicantStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid");
1018 if (networkHandle == null) return false;
1019 return networkHandle.setBssid(bssidStr);
1020 }
1021 }
1022
1023 /**
1024 * Get the currently configured network's WPS NFC token.
1025 *
1026 * @param ifaceName Name of the interface.
1027 * @return Hex string corresponding to the WPS NFC token.
1028 */
1029 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
1030 synchronized (mLock) {
1031 SupplicantStaNetworkHal networkHandle =
1032 checkSupplicantStaNetworkAndLogFailure(
1033 ifaceName, "getCurrentNetworkWpsNfcConfigurationToken");
1034 if (networkHandle == null) return null;
1035 return networkHandle.getWpsNfcConfigurationToken();
1036 }
1037 }
1038
1039 /**
1040 * Get the eap anonymous identity for the currently configured network.
1041 *
1042 * @param ifaceName Name of the interface.
1043 * @return anonymous identity string if succeeds, null otherwise.
1044 */
1045 public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) {
1046 synchronized (mLock) {
1047 SupplicantStaNetworkHal networkHandle =
1048 checkSupplicantStaNetworkAndLogFailure(
1049 ifaceName, "getCurrentNetworkEapAnonymousIdentity");
1050 if (networkHandle == null) return null;
1051 return networkHandle.fetchEapAnonymousIdentity();
1052 }
1053 }
1054
1055 /**
1056 * Send the eap identity response for the currently configured network.
1057 *
1058 * @param ifaceName Name of the interface.
1059 * @param identity identity used for EAP-Identity
1060 * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM
1061 * @return true if succeeds, false otherwise.
1062 */
1063 public boolean sendCurrentNetworkEapIdentityResponse(
1064 @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) {
1065 synchronized (mLock) {
1066 SupplicantStaNetworkHal networkHandle =
1067 checkSupplicantStaNetworkAndLogFailure(
1068 ifaceName, "sendCurrentNetworkEapIdentityResponse");
1069 if (networkHandle == null) return false;
1070 return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity);
1071 }
1072 }
1073
1074 /**
1075 * Send the eap sim gsm auth response for the currently configured network.
1076 *
1077 * @param ifaceName Name of the interface.
1078 * @param paramsStr String to send.
1079 * @return true if succeeds, false otherwise.
1080 */
1081 public boolean sendCurrentNetworkEapSimGsmAuthResponse(
1082 @NonNull String ifaceName, String paramsStr) {
1083 synchronized (mLock) {
1084 SupplicantStaNetworkHal networkHandle =
1085 checkSupplicantStaNetworkAndLogFailure(
1086 ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse");
1087 if (networkHandle == null) return false;
1088 return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
1089 }
1090 }
1091
1092 /**
1093 * Send the eap sim gsm auth failure for the currently configured network.
1094 *
1095 * @param ifaceName Name of the interface.
1096 * @return true if succeeds, false otherwise.
1097 */
1098 public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) {
1099 synchronized (mLock) {
1100 SupplicantStaNetworkHal networkHandle =
1101 checkSupplicantStaNetworkAndLogFailure(
1102 ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure");
1103 if (networkHandle == null) return false;
1104 return networkHandle.sendNetworkEapSimGsmAuthFailure();
1105 }
1106 }
1107
1108 /**
1109 * Send the eap sim umts auth response for the currently configured network.
1110 *
1111 * @param ifaceName Name of the interface.
1112 * @param paramsStr String to send.
1113 * @return true if succeeds, false otherwise.
1114 */
1115 public boolean sendCurrentNetworkEapSimUmtsAuthResponse(
1116 @NonNull String ifaceName, String paramsStr) {
1117 synchronized (mLock) {
1118 SupplicantStaNetworkHal networkHandle =
1119 checkSupplicantStaNetworkAndLogFailure(
1120 ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse");
1121 if (networkHandle == null) return false;
1122 return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
1123 }
1124 }
1125
1126 /**
1127 * Send the eap sim umts auts response for the currently configured network.
1128 *
1129 * @param ifaceName Name of the interface.
1130 * @param paramsStr String to send.
1131 * @return true if succeeds, false otherwise.
1132 */
1133 public boolean sendCurrentNetworkEapSimUmtsAutsResponse(
1134 @NonNull String ifaceName, String paramsStr) {
1135 synchronized (mLock) {
1136 SupplicantStaNetworkHal networkHandle =
1137 checkSupplicantStaNetworkAndLogFailure(
1138 ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse");
1139 if (networkHandle == null) return false;
1140 return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
1141 }
1142 }
1143
1144 /**
1145 * Send the eap sim umts auth failure for the currently configured network.
1146 *
1147 * @param ifaceName Name of the interface.
1148 * @return true if succeeds, false otherwise.
1149 */
1150 public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) {
1151 synchronized (mLock) {
1152 SupplicantStaNetworkHal networkHandle =
1153 checkSupplicantStaNetworkAndLogFailure(
1154 ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure");
1155 if (networkHandle == null) return false;
1156 return networkHandle.sendNetworkEapSimUmtsAuthFailure();
1157 }
1158 }
1159
1160 /**
1161 * Adds a new network.
1162 *
1163 * @return The ISupplicantNetwork object for the new network, or null if the call fails
1164 */
1165 private SupplicantStaNetworkHal addNetwork(@NonNull String ifaceName) {
1166 synchronized (mLock) {
1167 final String methodStr = "addNetwork";
1168 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1169 if (iface == null) return null;
1170 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
1171 try {
1172 iface.addNetwork((SupplicantStatus status,
1173 ISupplicantNetwork network) -> {
1174 if (checkStatusAndLogFailure(status, methodStr)) {
1175 newNetwork.value = network;
1176 }
1177 });
1178 } catch (RemoteException e) {
1179 handleRemoteException(e, methodStr);
1180 }
1181 if (newNetwork.value != null) {
1182 return getStaNetworkMockable(
1183 ifaceName,
1184 ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
1185 } else {
1186 return null;
1187 }
1188 }
1189 }
1190
1191 /**
1192 * Remove network from supplicant with network Id
1193 *
1194 * @return true if request is sent successfully, false otherwise.
1195 */
1196 private boolean removeNetwork(@NonNull String ifaceName, int id) {
1197 synchronized (mLock) {
1198 final String methodStr = "removeNetwork";
1199 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1200 if (iface == null) return false;
1201 try {
1202 SupplicantStatus status = iface.removeNetwork(id);
1203 return checkStatusAndLogFailure(status, methodStr);
1204 } catch (RemoteException e) {
1205 handleRemoteException(e, methodStr);
1206 return false;
1207 }
1208 }
1209 }
1210
1211 /**
1212 * Use this to mock the creation of SupplicantStaNetworkHal instance.
1213 *
1214 * @param ifaceName Name of the interface.
1215 * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL.
1216 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
1217 * the call fails
1218 */
1219 protected SupplicantStaNetworkHal getStaNetworkMockable(
1220 @NonNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork) {
1221 synchronized (mLock) {
1222 SupplicantStaNetworkHal network =
1223 new SupplicantStaNetworkHal(iSupplicantStaNetwork, ifaceName, mContext,
1224 mWifiMonitor);
1225 if (network != null) {
1226 network.enableVerboseLogging(mVerboseLoggingEnabled);
1227 }
1228 return network;
1229 }
1230 }
1231
1232 /**
1233 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
1234 * the call fails
1235 */
1236 private SupplicantStaNetworkHal getNetwork(@NonNull String ifaceName, int id) {
1237 synchronized (mLock) {
1238 final String methodStr = "getNetwork";
1239 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1240 if (iface == null) return null;
1241 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>();
1242 try {
1243 iface.getNetwork(id, (SupplicantStatus status, ISupplicantNetwork network) -> {
1244 if (checkStatusAndLogFailure(status, methodStr)) {
1245 gotNetwork.value = network;
1246 }
1247 });
1248 } catch (RemoteException e) {
1249 handleRemoteException(e, methodStr);
1250 }
1251 if (gotNetwork.value != null) {
1252 return getStaNetworkMockable(
1253 ifaceName,
1254 ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
1255 } else {
1256 return null;
1257 }
1258 }
1259 }
1260
1261 /** See ISupplicantStaNetwork.hal for documentation */
1262 private boolean registerCallback(
1263 ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) {
1264 synchronized (mLock) {
1265 final String methodStr = "registerCallback";
1266 if (iface == null) return false;
1267 try {
1268 SupplicantStatus status = iface.registerCallback(callback);
1269 return checkStatusAndLogFailure(status, methodStr);
1270 } catch (RemoteException e) {
1271 handleRemoteException(e, methodStr);
1272 return false;
1273 }
1274 }
1275 }
1276
1277 private boolean registerCallbackV1_1(
1278 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface,
1279 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback) {
1280 synchronized (mLock) {
1281 String methodStr = "registerCallback_1_1";
1282
1283 if (iface == null) return false;
1284 try {
1285 SupplicantStatus status = iface.registerCallback_1_1(callback);
1286 return checkStatusAndLogFailure(status, methodStr);
1287 } catch (RemoteException e) {
1288 handleRemoteException(e, methodStr);
1289 return false;
1290 }
1291 }
1292 }
1293
1294 private boolean registerCallbackV1_2(
1295 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface,
1296 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback callback) {
1297 synchronized (mLock) {
1298 String methodStr = "registerCallback_1_2";
1299
1300 if (iface == null) return false;
1301 try {
1302 SupplicantStatus status = iface.registerCallback_1_2(callback);
1303 return checkStatusAndLogFailure(status, methodStr);
1304 } catch (RemoteException e) {
1305 handleRemoteException(e, methodStr);
1306 return false;
1307 }
1308 }
1309 }
1310
1311 /**
1312 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
1313 * null if the call fails
1314 */
1315 private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) {
1316 synchronized (mLock) {
1317 final String methodStr = "listNetworks";
1318 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1319 if (iface == null) return null;
1320 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
1321 try {
1322 iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> {
1323 if (checkStatusAndLogFailure(status, methodStr)) {
1324 networkIdList.value = networkIds;
1325 }
1326 });
1327 } catch (RemoteException e) {
1328 handleRemoteException(e, methodStr);
1329 }
1330 return networkIdList.value;
1331 }
1332 }
1333
1334 /**
1335 * Set WPS device name.
1336 *
1337 * @param ifaceName Name of the interface.
1338 * @param name String to be set.
1339 * @return true if request is sent successfully, false otherwise.
1340 */
1341 public boolean setWpsDeviceName(@NonNull String ifaceName, String name) {
1342 synchronized (mLock) {
1343 final String methodStr = "setWpsDeviceName";
1344 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1345 if (iface == null) return false;
1346 try {
1347 SupplicantStatus status = iface.setWpsDeviceName(name);
1348 return checkStatusAndLogFailure(status, methodStr);
1349 } catch (RemoteException e) {
1350 handleRemoteException(e, methodStr);
1351 return false;
1352 }
1353 }
1354 }
1355
1356 /**
1357 * Set WPS device type.
1358 *
1359 * @param ifaceName Name of the interface.
1360 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
1361 * @return true if request is sent successfully, false otherwise.
1362 */
1363 public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) {
1364 synchronized (mLock) {
1365 try {
1366 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
1367 if (!match.find() || match.groupCount() != 3) {
1368 Log.e(TAG, "Malformed WPS device type " + typeStr);
1369 return false;
1370 }
1371 short categ = Short.parseShort(match.group(1));
1372 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
1373 short subCateg = Short.parseShort(match.group(3));
1374
1375 byte[] bytes = new byte[8];
1376 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
1377 byteBuffer.putShort(categ);
1378 byteBuffer.put(oui);
1379 byteBuffer.putShort(subCateg);
1380 return setWpsDeviceType(ifaceName, bytes);
1381 } catch (IllegalArgumentException e) {
1382 Log.e(TAG, "Illegal argument " + typeStr, e);
1383 return false;
1384 }
1385 }
1386 }
1387
1388 private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) {
1389 synchronized (mLock) {
1390 final String methodStr = "setWpsDeviceType";
1391 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1392 if (iface == null) return false;
1393 try {
1394 SupplicantStatus status = iface.setWpsDeviceType(type);
1395 return checkStatusAndLogFailure(status, methodStr);
1396 } catch (RemoteException e) {
1397 handleRemoteException(e, methodStr);
1398 return false;
1399 }
1400 }
1401 }
1402
1403 /**
1404 * Set WPS manufacturer.
1405 *
1406 * @param ifaceName Name of the interface.
1407 * @param manufacturer String to be set.
1408 * @return true if request is sent successfully, false otherwise.
1409 */
1410 public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) {
1411 synchronized (mLock) {
1412 final String methodStr = "setWpsManufacturer";
1413 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1414 if (iface == null) return false;
1415 try {
1416 SupplicantStatus status = iface.setWpsManufacturer(manufacturer);
1417 return checkStatusAndLogFailure(status, methodStr);
1418 } catch (RemoteException e) {
1419 handleRemoteException(e, methodStr);
1420 return false;
1421 }
1422 }
1423 }
1424
1425 /**
1426 * Set WPS model name.
1427 *
1428 * @param ifaceName Name of the interface.
1429 * @param modelName String to be set.
1430 * @return true if request is sent successfully, false otherwise.
1431 */
1432 public boolean setWpsModelName(@NonNull String ifaceName, String modelName) {
1433 synchronized (mLock) {
1434 final String methodStr = "setWpsModelName";
1435 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1436 if (iface == null) return false;
1437 try {
1438 SupplicantStatus status = iface.setWpsModelName(modelName);
1439 return checkStatusAndLogFailure(status, methodStr);
1440 } catch (RemoteException e) {
1441 handleRemoteException(e, methodStr);
1442 return false;
1443 }
1444 }
1445 }
1446
1447 /**
1448 * Set WPS model number.
1449 *
1450 * @param ifaceName Name of the interface.
1451 * @param modelNumber String to be set.
1452 * @return true if request is sent successfully, false otherwise.
1453 */
1454 public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) {
1455 synchronized (mLock) {
1456 final String methodStr = "setWpsModelNumber";
1457 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1458 if (iface == null) return false;
1459 try {
1460 SupplicantStatus status = iface.setWpsModelNumber(modelNumber);
1461 return checkStatusAndLogFailure(status, methodStr);
1462 } catch (RemoteException e) {
1463 handleRemoteException(e, methodStr);
1464 return false;
1465 }
1466 }
1467 }
1468
1469 /**
1470 * Set WPS serial number.
1471 *
1472 * @param ifaceName Name of the interface.
1473 * @param serialNumber String to be set.
1474 * @return true if request is sent successfully, false otherwise.
1475 */
1476 public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) {
1477 synchronized (mLock) {
1478 final String methodStr = "setWpsSerialNumber";
1479 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1480 if (iface == null) return false;
1481 try {
1482 SupplicantStatus status = iface.setWpsSerialNumber(serialNumber);
1483 return checkStatusAndLogFailure(status, methodStr);
1484 } catch (RemoteException e) {
1485 handleRemoteException(e, methodStr);
1486 return false;
1487 }
1488 }
1489 }
1490
1491 /**
1492 * Set WPS config methods
1493 *
1494 * @param ifaceName Name of the interface.
1495 * @param configMethodsStr List of config methods.
1496 * @return true if request is sent successfully, false otherwise.
1497 */
1498 public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) {
1499 synchronized (mLock) {
1500 short configMethodsMask = 0;
1501 String[] configMethodsStrArr = configMethodsStr.split("\\s+");
1502 for (int i = 0; i < configMethodsStrArr.length; i++) {
1503 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
1504 }
1505 return setWpsConfigMethods(ifaceName, configMethodsMask);
1506 }
1507 }
1508
1509 private boolean setWpsConfigMethods(@NonNull String ifaceName, short configMethods) {
1510 synchronized (mLock) {
1511 final String methodStr = "setWpsConfigMethods";
1512 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1513 if (iface == null) return false;
1514 try {
1515 SupplicantStatus status = iface.setWpsConfigMethods(configMethods);
1516 return checkStatusAndLogFailure(status, methodStr);
1517 } catch (RemoteException e) {
1518 handleRemoteException(e, methodStr);
1519 return false;
1520 }
1521 }
1522 }
1523
1524 /**
1525 * Trigger a reassociation even if the iface is currently connected.
1526 *
1527 * @param ifaceName Name of the interface.
1528 * @return true if request is sent successfully, false otherwise.
1529 */
1530 public boolean reassociate(@NonNull String ifaceName) {
1531 synchronized (mLock) {
1532 final String methodStr = "reassociate";
1533 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1534 if (iface == null) return false;
1535 try {
1536 SupplicantStatus status = iface.reassociate();
1537 return checkStatusAndLogFailure(status, methodStr);
1538 } catch (RemoteException e) {
1539 handleRemoteException(e, methodStr);
1540 return false;
1541 }
1542 }
1543 }
1544
1545 /**
1546 * Trigger a reconnection if the iface is disconnected.
1547 *
1548 * @param ifaceName Name of the interface.
1549 * @return true if request is sent successfully, false otherwise.
1550 */
1551 public boolean reconnect(@NonNull String ifaceName) {
1552 synchronized (mLock) {
1553 final String methodStr = "reconnect";
1554 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1555 if (iface == null) return false;
1556 try {
1557 SupplicantStatus status = iface.reconnect();
1558 return checkStatusAndLogFailure(status, methodStr);
1559 } catch (RemoteException e) {
1560 handleRemoteException(e, methodStr);
1561 return false;
1562 }
1563 }
1564 }
1565
1566 /**
1567 * Trigger a disconnection from the currently connected network.
1568 *
1569 * @param ifaceName Name of the interface.
1570 * @return true if request is sent successfully, false otherwise.
1571 */
1572 public boolean disconnect(@NonNull String ifaceName) {
1573 synchronized (mLock) {
1574 final String methodStr = "disconnect";
1575 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1576 if (iface == null) return false;
1577 try {
1578 SupplicantStatus status = iface.disconnect();
1579 return checkStatusAndLogFailure(status, methodStr);
1580 } catch (RemoteException e) {
1581 handleRemoteException(e, methodStr);
1582 return false;
1583 }
1584 }
1585 }
1586
1587 /**
1588 * Enable or disable power save mode.
1589 *
1590 * @param ifaceName Name of the interface.
1591 * @param enable true to enable, false to disable.
1592 * @return true if request is sent successfully, false otherwise.
1593 */
1594 public boolean setPowerSave(@NonNull String ifaceName, boolean enable) {
1595 synchronized (mLock) {
1596 final String methodStr = "setPowerSave";
1597 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1598 if (iface == null) return false;
1599 try {
1600 SupplicantStatus status = iface.setPowerSave(enable);
1601 return checkStatusAndLogFailure(status, methodStr);
1602 } catch (RemoteException e) {
1603 handleRemoteException(e, methodStr);
1604 return false;
1605 }
1606 }
1607 }
1608
1609 /**
1610 * Initiate TDLS discover with the specified AP.
1611 *
1612 * @param ifaceName Name of the interface.
1613 * @param macAddress MAC Address of the AP.
1614 * @return true if request is sent successfully, false otherwise.
1615 */
1616 public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) {
1617 synchronized (mLock) {
1618 try {
1619 return initiateTdlsDiscover(
1620 ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1621 } catch (IllegalArgumentException e) {
1622 Log.e(TAG, "Illegal argument " + macAddress, e);
1623 return false;
1624 }
1625 }
1626 }
1627 /** See ISupplicantStaIface.hal for documentation */
1628 private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1629 synchronized (mLock) {
1630 final String methodStr = "initiateTdlsDiscover";
1631 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1632 if (iface == null) return false;
1633 try {
1634 SupplicantStatus status = iface.initiateTdlsDiscover(macAddress);
1635 return checkStatusAndLogFailure(status, methodStr);
1636 } catch (RemoteException e) {
1637 handleRemoteException(e, methodStr);
1638 return false;
1639 }
1640 }
1641 }
1642
1643 /**
1644 * Initiate TDLS setup with the specified AP.
1645 *
1646 * @param ifaceName Name of the interface.
1647 * @param macAddress MAC Address of the AP.
1648 * @return true if request is sent successfully, false otherwise.
1649 */
1650 public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) {
1651 synchronized (mLock) {
1652 try {
1653 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1654 } catch (IllegalArgumentException e) {
1655 Log.e(TAG, "Illegal argument " + macAddress, e);
1656 return false;
1657 }
1658 }
1659 }
1660 /** See ISupplicantStaIface.hal for documentation */
1661 private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1662 synchronized (mLock) {
1663 final String methodStr = "initiateTdlsSetup";
1664 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1665 if (iface == null) return false;
1666 try {
1667 SupplicantStatus status = iface.initiateTdlsSetup(macAddress);
1668 return checkStatusAndLogFailure(status, methodStr);
1669 } catch (RemoteException e) {
1670 handleRemoteException(e, methodStr);
1671 return false;
1672 }
1673 }
1674 }
1675
1676 /**
1677 * Initiate TDLS teardown with the specified AP.
1678 * @param ifaceName Name of the interface.
1679 * @param macAddress MAC Address of the AP.
1680 * @return true if request is sent successfully, false otherwise.
1681 */
1682 public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) {
1683 synchronized (mLock) {
1684 try {
1685 return initiateTdlsTeardown(
1686 ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1687 } catch (IllegalArgumentException e) {
1688 Log.e(TAG, "Illegal argument " + macAddress, e);
1689 return false;
1690 }
1691 }
1692 }
1693
1694 /** See ISupplicantStaIface.hal for documentation */
1695 private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1696 synchronized (mLock) {
1697 final String methodStr = "initiateTdlsTeardown";
1698 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1699 if (iface == null) return false;
1700 try {
1701 SupplicantStatus status = iface.initiateTdlsTeardown(macAddress);
1702 return checkStatusAndLogFailure(status, methodStr);
1703 } catch (RemoteException e) {
1704 handleRemoteException(e, methodStr);
1705 return false;
1706 }
1707 }
1708 }
1709
1710 /**
1711 * Request the specified ANQP elements |elements| from the specified AP |bssid|.
1712 *
1713 * @param ifaceName Name of the interface.
1714 * @param bssid BSSID of the AP
1715 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
1716 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
1717 * @return true if request is sent successfully, false otherwise.
1718 */
1719 public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid,
1720 ArrayList<Short> infoElements,
1721 ArrayList<Integer> hs20SubTypes) {
1722 synchronized (mLock) {
1723 try {
1724 return initiateAnqpQuery(
1725 ifaceName,
1726 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes);
1727 } catch (IllegalArgumentException e) {
1728 Log.e(TAG, "Illegal argument " + bssid, e);
1729 return false;
1730 }
1731 }
1732 }
1733
1734 /** See ISupplicantStaIface.hal for documentation */
1735 private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress,
1736 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) {
1737 synchronized (mLock) {
1738 final String methodStr = "initiateAnqpQuery";
1739 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1740 if (iface == null) return false;
1741 try {
1742 SupplicantStatus status = iface.initiateAnqpQuery(
1743 macAddress, infoElements, subTypes);
1744 return checkStatusAndLogFailure(status, methodStr);
1745 } catch (RemoteException e) {
1746 handleRemoteException(e, methodStr);
1747 return false;
1748 }
1749 }
1750 }
1751
1752 /**
1753 * Request the specified ANQP ICON from the specified AP |bssid|.
1754 *
1755 * @param ifaceName Name of the interface.
1756 * @param bssid BSSID of the AP
1757 * @param fileName Name of the file to request.
1758 * @return true if request is sent successfully, false otherwise.
1759 */
1760 public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) {
1761 synchronized (mLock) {
1762 try {
1763 return initiateHs20IconQuery(
1764 ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName);
1765 } catch (IllegalArgumentException e) {
1766 Log.e(TAG, "Illegal argument " + bssid, e);
1767 return false;
1768 }
1769 }
1770 }
1771
1772 /** See ISupplicantStaIface.hal for documentation */
1773 private boolean initiateHs20IconQuery(@NonNull String ifaceName,
1774 byte[/* 6 */] macAddress, String fileName) {
1775 synchronized (mLock) {
1776 final String methodStr = "initiateHs20IconQuery";
1777 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1778 if (iface == null) return false;
1779 try {
1780 SupplicantStatus status = iface.initiateHs20IconQuery(macAddress, fileName);
1781 return checkStatusAndLogFailure(status, methodStr);
1782 } catch (RemoteException e) {
1783 handleRemoteException(e, methodStr);
1784 return false;
1785 }
1786 }
1787 }
1788
1789 /**
1790 * Makes a callback to HIDL to getMacAddress from supplicant
1791 *
1792 * @param ifaceName Name of the interface.
1793 * @return string containing the MAC address, or null on a failed call
1794 */
1795 public String getMacAddress(@NonNull String ifaceName) {
1796 synchronized (mLock) {
1797 final String methodStr = "getMacAddress";
1798 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1799 if (iface == null) return null;
1800 Mutable<String> gotMac = new Mutable<>();
1801 try {
1802 iface.getMacAddress((SupplicantStatus status,
1803 byte[/* 6 */] macAddr) -> {
1804 if (checkStatusAndLogFailure(status, methodStr)) {
1805 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
1806 }
1807 });
1808 } catch (RemoteException e) {
1809 handleRemoteException(e, methodStr);
1810 }
1811 return gotMac.value;
1812 }
1813 }
1814
1815 /**
1816 * Start using the added RX filters.
1817 *
1818 * @param ifaceName Name of the interface.
1819 * @return true if request is sent successfully, false otherwise.
1820 */
1821 public boolean startRxFilter(@NonNull String ifaceName) {
1822 synchronized (mLock) {
1823 final String methodStr = "startRxFilter";
1824 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1825 if (iface == null) return false;
1826 try {
1827 SupplicantStatus status = iface.startRxFilter();
1828 return checkStatusAndLogFailure(status, methodStr);
1829 } catch (RemoteException e) {
1830 handleRemoteException(e, methodStr);
1831 return false;
1832 }
1833 }
1834 }
1835
1836 /**
1837 * Stop using the added RX filters.
1838 *
1839 * @param ifaceName Name of the interface.
1840 * @return true if request is sent successfully, false otherwise.
1841 */
1842 public boolean stopRxFilter(@NonNull String ifaceName) {
1843 synchronized (mLock) {
1844 final String methodStr = "stopRxFilter";
1845 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1846 if (iface == null) return false;
1847 try {
1848 SupplicantStatus status = iface.stopRxFilter();
1849 return checkStatusAndLogFailure(status, methodStr);
1850 } catch (RemoteException e) {
1851 handleRemoteException(e, methodStr);
1852 return false;
1853 }
1854 }
1855 }
1856
1857 /**
1858 * Add an RX filter.
1859 *
1860 * @param ifaceName Name of the interface.
1861 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1862 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1863 * @return true if request is sent successfully, false otherwise.
1864 */
1865 public boolean addRxFilter(@NonNull String ifaceName, int type) {
1866 synchronized (mLock) {
1867 byte halType;
1868 switch (type) {
1869 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1870 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST;
1871 break;
1872 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1873 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1874 break;
1875 default:
1876 Log.e(TAG, "Invalid Rx Filter type: " + type);
1877 return false;
1878 }
1879 return addRxFilter(ifaceName, halType);
1880 }
1881 }
1882
1883 private boolean addRxFilter(@NonNull String ifaceName, byte type) {
1884 synchronized (mLock) {
1885 final String methodStr = "addRxFilter";
1886 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1887 if (iface == null) return false;
1888 try {
1889 SupplicantStatus status = iface.addRxFilter(type);
1890 return checkStatusAndLogFailure(status, methodStr);
1891 } catch (RemoteException e) {
1892 handleRemoteException(e, methodStr);
1893 return false;
1894 }
1895 }
1896 }
1897
1898 /**
1899 * Remove an RX filter.
1900 *
1901 * @param ifaceName Name of the interface.
1902 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1903 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1904 * @return true if request is sent successfully, false otherwise.
1905 */
1906 public boolean removeRxFilter(@NonNull String ifaceName, int type) {
1907 synchronized (mLock) {
1908 byte halType;
1909 switch (type) {
1910 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1911 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST;
1912 break;
1913 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1914 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1915 break;
1916 default:
1917 Log.e(TAG, "Invalid Rx Filter type: " + type);
1918 return false;
1919 }
1920 return removeRxFilter(ifaceName, halType);
1921 }
1922 }
1923
1924 private boolean removeRxFilter(@NonNull String ifaceName, byte type) {
1925 synchronized (mLock) {
1926 final String methodStr = "removeRxFilter";
1927 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1928 if (iface == null) return false;
1929 try {
1930 SupplicantStatus status = iface.removeRxFilter(type);
1931 return checkStatusAndLogFailure(status, methodStr);
1932 } catch (RemoteException e) {
1933 handleRemoteException(e, methodStr);
1934 return false;
1935 }
1936 }
1937 }
1938
1939 /**
1940 * Set Bt co existense mode.
1941 *
1942 * @param ifaceName Name of the interface.
1943 * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
1944 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
1945 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
1946 * @return true if request is sent successfully, false otherwise.
1947 */
1948 public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) {
1949 synchronized (mLock) {
1950 byte halMode;
1951 switch (mode) {
1952 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED:
1953 halMode = ISupplicantStaIface.BtCoexistenceMode.ENABLED;
1954 break;
1955 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED:
1956 halMode = ISupplicantStaIface.BtCoexistenceMode.DISABLED;
1957 break;
1958 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE:
1959 halMode = ISupplicantStaIface.BtCoexistenceMode.SENSE;
1960 break;
1961 default:
1962 Log.e(TAG, "Invalid Bt Coex mode: " + mode);
1963 return false;
1964 }
1965 return setBtCoexistenceMode(ifaceName, halMode);
1966 }
1967 }
1968
1969 private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) {
1970 synchronized (mLock) {
1971 final String methodStr = "setBtCoexistenceMode";
1972 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1973 if (iface == null) return false;
1974 try {
1975 SupplicantStatus status = iface.setBtCoexistenceMode(mode);
1976 return checkStatusAndLogFailure(status, methodStr);
1977 } catch (RemoteException e) {
1978 handleRemoteException(e, methodStr);
1979 return false;
1980 }
1981 }
1982 }
1983
1984 /** Enable or disable BT coexistence mode.
1985 *
1986 * @param ifaceName Name of the interface.
1987 * @param enable true to enable, false to disable.
1988 * @return true if request is sent successfully, false otherwise.
1989 */
1990 public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) {
1991 synchronized (mLock) {
1992 final String methodStr = "setBtCoexistenceScanModeEnabled";
1993 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1994 if (iface == null) return false;
1995 try {
1996 SupplicantStatus status =
1997 iface.setBtCoexistenceScanModeEnabled(enable);
1998 return checkStatusAndLogFailure(status, methodStr);
1999 } catch (RemoteException e) {
2000 handleRemoteException(e, methodStr);
2001 return false;
2002 }
2003 }
2004 }
2005
2006 /**
2007 * Enable or disable suspend mode optimizations.
2008 *
2009 * @param ifaceName Name of the interface.
2010 * @param enable true to enable, false otherwise.
2011 * @return true if request is sent successfully, false otherwise.
2012 */
2013 public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) {
2014 synchronized (mLock) {
2015 final String methodStr = "setSuspendModeEnabled";
2016 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2017 if (iface == null) return false;
2018 try {
2019 SupplicantStatus status = iface.setSuspendModeEnabled(enable);
2020 return checkStatusAndLogFailure(status, methodStr);
2021 } catch (RemoteException e) {
2022 handleRemoteException(e, methodStr);
2023 return false;
2024 }
2025 }
2026 }
2027
2028 /**
2029 * Set country code.
2030 *
2031 * @param ifaceName Name of the interface.
2032 * @param codeStr 2 byte ASCII string. For ex: US, CA.
2033 * @return true if request is sent successfully, false otherwise.
2034 */
2035 public boolean setCountryCode(@NonNull String ifaceName, String codeStr) {
2036 synchronized (mLock) {
2037 if (TextUtils.isEmpty(codeStr)) return false;
2038 byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr);
2039 if (countryCodeBytes.length != 2) return false;
2040 return setCountryCode(ifaceName, countryCodeBytes);
2041 }
2042 }
2043
2044 /** See ISupplicantStaIface.hal for documentation */
2045 private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) {
2046 synchronized (mLock) {
2047 final String methodStr = "setCountryCode";
2048 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2049 if (iface == null) return false;
2050 try {
2051 SupplicantStatus status = iface.setCountryCode(code);
2052 return checkStatusAndLogFailure(status, methodStr);
2053 } catch (RemoteException e) {
2054 handleRemoteException(e, methodStr);
2055 return false;
2056 }
2057 }
2058 }
2059
2060 /**
2061 * Start WPS pin registrar operation with the specified peer and pin.
2062 *
2063 * @param ifaceName Name of the interface.
2064 * @param bssidStr BSSID of the peer.
2065 * @param pin Pin to be used.
2066 * @return true if request is sent successfully, false otherwise.
2067 */
2068 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) {
2069 synchronized (mLock) {
2070 if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false;
2071 try {
2072 return startWpsRegistrar(
2073 ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin);
2074 } catch (IllegalArgumentException e) {
2075 Log.e(TAG, "Illegal argument " + bssidStr, e);
2076 return false;
2077 }
2078 }
2079 }
2080
2081 /** See ISupplicantStaIface.hal for documentation */
2082 private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) {
2083 synchronized (mLock) {
2084 final String methodStr = "startWpsRegistrar";
2085 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2086 if (iface == null) return false;
2087 try {
2088 SupplicantStatus status = iface.startWpsRegistrar(bssid, pin);
2089 return checkStatusAndLogFailure(status, methodStr);
2090 } catch (RemoteException e) {
2091 handleRemoteException(e, methodStr);
2092 return false;
2093 }
2094 }
2095 }
2096
2097 /**
2098 * Start WPS pin display operation with the specified peer.
2099 *
2100 * @param ifaceName Name of the interface.
2101 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2102 * @return true if request is sent successfully, false otherwise.
2103 */
2104 public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) {
2105 synchronized (mLock) {
2106 try {
2107 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2108 } catch (IllegalArgumentException e) {
2109 Log.e(TAG, "Illegal argument " + bssidStr, e);
2110 return false;
2111 }
2112 }
2113 }
2114
2115 /** See ISupplicantStaIface.hal for documentation */
2116 private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2117 synchronized (mLock) {
2118 final String methodStr = "startWpsPbc";
2119 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2120 if (iface == null) return false;
2121 try {
2122 SupplicantStatus status = iface.startWpsPbc(bssid);
2123 return checkStatusAndLogFailure(status, methodStr);
2124 } catch (RemoteException e) {
2125 handleRemoteException(e, methodStr);
2126 return false;
2127 }
2128 }
2129 }
2130
2131 /**
2132 * Start WPS pin keypad operation with the specified pin.
2133 *
2134 * @param ifaceName Name of the interface.
2135 * @param pin Pin to be used.
2136 * @return true if request is sent successfully, false otherwise.
2137 */
2138 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2139 if (TextUtils.isEmpty(pin)) return false;
2140 synchronized (mLock) {
2141 final String methodStr = "startWpsPinKeypad";
2142 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2143 if (iface == null) return false;
2144 try {
2145 SupplicantStatus status = iface.startWpsPinKeypad(pin);
2146 return checkStatusAndLogFailure(status, methodStr);
2147 } catch (RemoteException e) {
2148 handleRemoteException(e, methodStr);
2149 return false;
2150 }
2151 }
2152 }
2153
2154 /**
2155 * Start WPS pin display operation with the specified peer.
2156 *
2157 * @param ifaceName Name of the interface.
2158 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2159 * @return new pin generated on success, null otherwise.
2160 */
2161 public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) {
2162 synchronized (mLock) {
2163 try {
2164 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2165 } catch (IllegalArgumentException e) {
2166 Log.e(TAG, "Illegal argument " + bssidStr, e);
2167 return null;
2168 }
2169 }
2170 }
2171
2172 /** See ISupplicantStaIface.hal for documentation */
2173 private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2174 synchronized (mLock) {
2175 final String methodStr = "startWpsPinDisplay";
2176 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2177 if (iface == null) return null;
2178 final Mutable<String> gotPin = new Mutable<>();
2179 try {
2180 iface.startWpsPinDisplay(bssid,
2181 (SupplicantStatus status, String pin) -> {
2182 if (checkStatusAndLogFailure(status, methodStr)) {
2183 gotPin.value = pin;
2184 }
2185 });
2186 } catch (RemoteException e) {
2187 handleRemoteException(e, methodStr);
2188 }
2189 return gotPin.value;
2190 }
2191 }
2192
2193 /**
2194 * Cancels any ongoing WPS requests.
2195 *
2196 * @param ifaceName Name of the interface.
2197 * @return true if request is sent successfully, false otherwise.
2198 */
2199 public boolean cancelWps(@NonNull String ifaceName) {
2200 synchronized (mLock) {
2201 final String methodStr = "cancelWps";
2202 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2203 if (iface == null) return false;
2204 try {
2205 SupplicantStatus status = iface.cancelWps();
2206 return checkStatusAndLogFailure(status, methodStr);
2207 } catch (RemoteException e) {
2208 handleRemoteException(e, methodStr);
2209 return false;
2210 }
2211 }
2212 }
2213
2214 /**
2215 * Sets whether to use external sim for SIM/USIM processing.
2216 *
2217 * @param ifaceName Name of the interface.
2218 * @param useExternalSim true to enable, false otherwise.
2219 * @return true if request is sent successfully, false otherwise.
2220 */
2221 public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) {
2222 synchronized (mLock) {
2223 final String methodStr = "setExternalSim";
2224 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2225 if (iface == null) return false;
2226 try {
2227 SupplicantStatus status = iface.setExternalSim(useExternalSim);
2228 return checkStatusAndLogFailure(status, methodStr);
2229 } catch (RemoteException e) {
2230 handleRemoteException(e, methodStr);
2231 return false;
2232 }
2233 }
2234 }
2235
2236 /** See ISupplicant.hal for documentation */
2237 public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) {
2238 synchronized (mLock) {
2239 final String methodStr = "enableAutoReconnect";
2240 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
2241 if (iface == null) return false;
2242 try {
2243 SupplicantStatus status = iface.enableAutoReconnect(enable);
2244 return checkStatusAndLogFailure(status, methodStr);
2245 } catch (RemoteException e) {
2246 handleRemoteException(e, methodStr);
2247 return false;
2248 }
2249 }
2250 }
2251
2252 /**
2253 * Set the debug log level for wpa_supplicant
2254 *
2255 * @param turnOnVerbose Whether to turn on verbose logging or not.
2256 * @return true if request is sent successfully, false otherwise.
2257 */
2258 public boolean setLogLevel(boolean turnOnVerbose) {
2259 synchronized (mLock) {
2260 int logLevel = turnOnVerbose
2261 ? ISupplicant.DebugLevel.DEBUG
2262 : ISupplicant.DebugLevel.INFO;
2263 return setDebugParams(logLevel, false, false);
2264 }
2265 }
2266
2267 /** See ISupplicant.hal for documentation */
2268 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
2269 synchronized (mLock) {
2270 final String methodStr = "setDebugParams";
2271 if (!checkSupplicantAndLogFailure(methodStr)) return false;
2272 try {
2273 SupplicantStatus status =
2274 mISupplicant.setDebugParams(level, showTimestamp, showKeys);
2275 return checkStatusAndLogFailure(status, methodStr);
2276 } catch (RemoteException e) {
2277 handleRemoteException(e, methodStr);
2278 return false;
2279 }
2280 }
2281 }
2282
2283 /**
2284 * Set concurrency priority between P2P & STA operations.
2285 *
2286 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2287 * false otherwise.
2288 * @return true if request is sent successfully, false otherwise.
2289 */
2290 public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2291 synchronized (mLock) {
2292 if (isStaHigherPriority) {
2293 return setConcurrencyPriority(IfaceType.STA);
2294 } else {
2295 return setConcurrencyPriority(IfaceType.P2P);
2296 }
2297 }
2298 }
2299
2300 /** See ISupplicant.hal for documentation */
2301 private boolean setConcurrencyPriority(int type) {
2302 synchronized (mLock) {
2303 final String methodStr = "setConcurrencyPriority";
2304 if (!checkSupplicantAndLogFailure(methodStr)) return false;
2305 try {
2306 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type);
2307 return checkStatusAndLogFailure(status, methodStr);
2308 } catch (RemoteException e) {
2309 handleRemoteException(e, methodStr);
2310 return false;
2311 }
2312 }
2313 }
2314
2315 /**
2316 * Returns false if Supplicant is null, and logs failure to call methodStr
2317 */
2318 private boolean checkSupplicantAndLogFailure(final String methodStr) {
2319 synchronized (mLock) {
2320 if (mISupplicant == null) {
2321 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
2322 return false;
2323 }
2324 return true;
2325 }
2326 }
2327
2328 /**
2329 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr
2330 */
2331 private ISupplicantStaIface checkSupplicantStaIfaceAndLogFailure(
2332 @NonNull String ifaceName, final String methodStr) {
2333 synchronized (mLock) {
2334 ISupplicantStaIface iface = getStaIface(ifaceName);
2335 if (iface == null) {
2336 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null");
2337 return null;
2338 }
2339 return iface;
2340 }
2341 }
2342
2343 /**
2344 * Returns false if SupplicantStaNetwork is null, and logs failure to call methodStr
2345 */
2346 private SupplicantStaNetworkHal checkSupplicantStaNetworkAndLogFailure(
2347 @NonNull String ifaceName, final String methodStr) {
2348 synchronized (mLock) {
2349 SupplicantStaNetworkHal networkHal = getCurrentNetworkRemoteHandle(ifaceName);
2350 if (networkHal == null) {
2351 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork is null");
2352 return null;
2353 }
2354 return networkHal;
2355 }
2356 }
2357
2358 /**
2359 * Returns true if provided status code is SUCCESS, logs debug message and returns false
2360 * otherwise
2361 */
2362 private boolean checkStatusAndLogFailure(SupplicantStatus status,
2363 final String methodStr) {
2364 synchronized (mLock) {
2365 if (status.code != SupplicantStatusCode.SUCCESS) {
2366 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " + status);
2367 return false;
2368 } else {
2369 if (mVerboseLoggingEnabled) {
2370 Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded");
2371 }
2372 return true;
2373 }
2374 }
2375 }
2376
2377 /**
2378 * Helper function to log callbacks.
2379 */
2380 private void logCallback(final String methodStr) {
2381 synchronized (mLock) {
2382 if (mVerboseLoggingEnabled) {
2383 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received");
2384 }
2385 }
2386 }
2387
2388 private void handleNoSuchElementException(NoSuchElementException e, String methodStr) {
2389 synchronized (mLock) {
2390 clearState();
2391 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e);
2392 }
2393 }
2394
2395 private void handleRemoteException(RemoteException e, String methodStr) {
2396 synchronized (mLock) {
2397 clearState();
2398 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e);
2399 }
2400 }
2401
2402 /**
2403 * Converts the Wps config method string to the equivalent enum value.
2404 */
2405 private static short stringToWpsConfigMethod(String configMethod) {
2406 switch (configMethod) {
2407 case "usba":
2408 return WpsConfigMethods.USBA;
2409 case "ethernet":
2410 return WpsConfigMethods.ETHERNET;
2411 case "label":
2412 return WpsConfigMethods.LABEL;
2413 case "display":
2414 return WpsConfigMethods.DISPLAY;
2415 case "int_nfc_token":
2416 return WpsConfigMethods.INT_NFC_TOKEN;
2417 case "ext_nfc_token":
2418 return WpsConfigMethods.EXT_NFC_TOKEN;
2419 case "nfc_interface":
2420 return WpsConfigMethods.NFC_INTERFACE;
2421 case "push_button":
2422 return WpsConfigMethods.PUSHBUTTON;
2423 case "keypad":
2424 return WpsConfigMethods.KEYPAD;
2425 case "virtual_push_button":
2426 return WpsConfigMethods.VIRT_PUSHBUTTON;
2427 case "physical_push_button":
2428 return WpsConfigMethods.PHY_PUSHBUTTON;
2429 case "p2ps":
2430 return WpsConfigMethods.P2PS;
2431 case "virtual_display":
2432 return WpsConfigMethods.VIRT_DISPLAY;
2433 case "physical_display":
2434 return WpsConfigMethods.PHY_DISPLAY;
2435 default:
2436 throw new IllegalArgumentException(
2437 "Invalid WPS config method: " + configMethod);
2438 }
2439 }
2440
2441 /**
2442 * Converts the supplicant state received from HIDL to the equivalent framework state.
2443 */
2444 private static SupplicantState supplicantHidlStateToFrameworkState(int state) {
2445 switch (state) {
2446 case ISupplicantStaIfaceCallback.State.DISCONNECTED:
2447 return SupplicantState.DISCONNECTED;
2448 case ISupplicantStaIfaceCallback.State.IFACE_DISABLED:
2449 return SupplicantState.INTERFACE_DISABLED;
2450 case ISupplicantStaIfaceCallback.State.INACTIVE:
2451 return SupplicantState.INACTIVE;
2452 case ISupplicantStaIfaceCallback.State.SCANNING:
2453 return SupplicantState.SCANNING;
2454 case ISupplicantStaIfaceCallback.State.AUTHENTICATING:
2455 return SupplicantState.AUTHENTICATING;
2456 case ISupplicantStaIfaceCallback.State.ASSOCIATING:
2457 return SupplicantState.ASSOCIATING;
2458 case ISupplicantStaIfaceCallback.State.ASSOCIATED:
2459 return SupplicantState.ASSOCIATED;
2460 case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE:
2461 return SupplicantState.FOUR_WAY_HANDSHAKE;
2462 case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE:
2463 return SupplicantState.GROUP_HANDSHAKE;
2464 case ISupplicantStaIfaceCallback.State.COMPLETED:
2465 return SupplicantState.COMPLETED;
2466 default:
2467 throw new IllegalArgumentException("Invalid state: " + state);
2468 }
2469 }
2470
2471 private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub {
2472 private String mIfaceName;
2473 private boolean mStateIsFourway = false; // Used to help check for PSK password mismatch
2474
2475 SupplicantStaIfaceHalCallback(@NonNull String ifaceName) {
2476 mIfaceName = ifaceName;
2477 }
2478
2479 /**
2480 * Parses the provided payload into an ANQP element.
2481 *
2482 * @param infoID Element type.
2483 * @param payload Raw payload bytes.
2484 * @return AnqpElement instance on success, null on failure.
2485 */
2486 private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID,
2487 ArrayList<Byte> payload) {
2488 synchronized (mLock) {
2489 try {
2490 return Constants.getANQPElementID(infoID) != null
2491 ? ANQPParser.parseElement(
2492 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)))
2493 : ANQPParser.parseHS20Element(
2494 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)));
2495 } catch (IOException | BufferUnderflowException e) {
2496 Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e);
2497 return null;
2498 }
2499 }
2500 }
2501
2502 /**
2503 * Parse the ANQP element data and add to the provided elements map if successful.
2504 *
2505 * @param elementsMap Map to add the parsed out element to.
2506 * @param infoID Element type.
2507 * @param payload Raw payload bytes.
2508 */
2509 private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap,
2510 Constants.ANQPElementType infoID,
2511 ArrayList<Byte> payload) {
2512 synchronized (mLock) {
2513 if (payload == null || payload.isEmpty()) return;
2514 ANQPElement element = parseAnqpElement(infoID, payload);
2515 if (element != null) {
2516 elementsMap.put(infoID, element);
2517 }
2518 }
2519 }
2520
2521 @Override
2522 public void onNetworkAdded(int id) {
2523 synchronized (mLock) {
2524 logCallback("onNetworkAdded");
2525 }
2526 }
2527
2528 @Override
2529 public void onNetworkRemoved(int id) {
2530 synchronized (mLock) {
2531 logCallback("onNetworkRemoved");
2532 // Reset 4way handshake state since network has been removed.
2533 mStateIsFourway = false;
2534 }
2535 }
2536
2537 @Override
2538 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
2539 ArrayList<Byte> ssid) {
2540 synchronized (mLock) {
2541 logCallback("onStateChanged");
2542 SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState);
2543 WifiSsid wifiSsid =
2544 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
2545 String bssidStr = NativeUtil.macAddressFromByteArray(bssid);
2546 mStateIsFourway = (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE);
2547 if (newSupplicantState == SupplicantState.COMPLETED) {
2548 mWifiMonitor.broadcastNetworkConnectionEvent(
2549 mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr);
2550 }
2551 mWifiMonitor.broadcastSupplicantStateChangeEvent(
2552 mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid,
2553 bssidStr, newSupplicantState);
2554 }
2555 }
2556
2557 @Override
2558 public void onAnqpQueryDone(byte[/* 6 */] bssid,
2559 ISupplicantStaIfaceCallback.AnqpData data,
2560 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
2561 synchronized (mLock) {
2562 logCallback("onAnqpQueryDone");
2563 Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>();
2564 addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName);
2565 addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium);
2566 addAnqpElementToMap(
2567 elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability);
2568 addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm);
2569 addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork);
2570 addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName);
2571 addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName);
2572 addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics);
2573 addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability);
2574 addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList);
2575 mWifiMonitor.broadcastAnqpDoneEvent(
2576 mIfaceName, new AnqpEvent(NativeUtil.macAddressToLong(bssid), elementsMap));
2577 }
2578 }
2579
2580 @Override
2581 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
2582 ArrayList<Byte> data) {
2583 synchronized (mLock) {
2584 logCallback("onHs20IconQueryDone");
2585 mWifiMonitor.broadcastIconDoneEvent(
2586 mIfaceName,
2587 new IconEvent(NativeUtil.macAddressToLong(bssid), fileName, data.size(),
2588 NativeUtil.byteArrayFromArrayList(data)));
2589 }
2590 }
2591
2592 @Override
2593 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) {
2594 synchronized (mLock) {
2595 logCallback("onHs20SubscriptionRemediation");
2596 mWifiMonitor.broadcastWnmEvent(
2597 mIfaceName,
2598 new WnmData(NativeUtil.macAddressToLong(bssid), url, osuMethod));
2599 }
2600 }
2601
2602 @Override
2603 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
2604 int reAuthDelayInSec, String url) {
2605 synchronized (mLock) {
2606 logCallback("onHs20DeauthImminentNotice");
2607 mWifiMonitor.broadcastWnmEvent(
2608 mIfaceName,
2609 new WnmData(NativeUtil.macAddressToLong(bssid), url,
2610 reasonCode == WnmData.ESS, reAuthDelayInSec));
2611 }
2612 }
2613
2614 @Override
2615 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) {
2616 synchronized (mLock) {
2617 logCallback("onDisconnected");
2618 if (mVerboseLoggingEnabled) {
2619 Log.e(TAG, "onDisconnected 4way=" + mStateIsFourway
2620 + " locallyGenerated=" + locallyGenerated
2621 + " reasonCode=" + reasonCode);
2622 }
2623 if (mStateIsFourway
2624 && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) {
2625 mWifiMonitor.broadcastAuthenticationFailureEvent(
2626 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1);
2627 }
2628 mWifiMonitor.broadcastNetworkDisconnectionEvent(
2629 mIfaceName, locallyGenerated ? 1 : 0, reasonCode,
2630 NativeUtil.macAddressFromByteArray(bssid));
2631 }
2632 }
2633
2634 @Override
2635 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, boolean timedOut) {
2636 synchronized (mLock) {
2637 logCallback("onAssociationRejected");
2638
2639 if (statusCode == StatusCode.UNSPECIFIED_FAILURE) {
2640 WifiConfiguration curConfiguration = getCurrentNetworkLocalConfig(mIfaceName);
2641
2642 if (curConfiguration != null
2643 && curConfiguration.allowedKeyManagement
2644 .get(WifiConfiguration.KeyMgmt.SAE)) {
2645 // Special handling for WPA3-Personal networks. If the password is
2646 // incorrect, the AP will send association rejection, with status code 1
2647 // (unspecified failure). In SAE networks, the password authentication
2648 // is not related to the 4-way handshake. In this case, we will send an
2649 // authentication failure event up.
2650 logCallback("SAE incorrect password");
2651 mWifiMonitor.broadcastAuthenticationFailureEvent(
2652 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1);
2653 }
2654 }
2655 mWifiMonitor.broadcastAssociationRejectionEvent(mIfaceName, statusCode, timedOut,
2656 NativeUtil.macAddressFromByteArray(bssid));
2657 }
2658 }
2659
2660 @Override
2661 public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
2662 synchronized (mLock) {
2663 logCallback("onAuthenticationTimeout");
2664 mWifiMonitor.broadcastAuthenticationFailureEvent(
2665 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_TIMEOUT, -1);
2666 }
2667 }
2668
2669 @Override
2670 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) {
2671 synchronized (mLock) {
2672 logCallback("onBssidChanged");
2673 if (reason == BssidChangeReason.ASSOC_START) {
2674 mWifiMonitor.broadcastTargetBssidEvent(
2675 mIfaceName, NativeUtil.macAddressFromByteArray(bssid));
2676 } else if (reason == BssidChangeReason.ASSOC_COMPLETE) {
2677 mWifiMonitor.broadcastAssociatedBssidEvent(
2678 mIfaceName, NativeUtil.macAddressFromByteArray(bssid));
2679 }
2680 }
2681 }
2682
2683 @Override
2684 public void onEapFailure() {
2685 synchronized (mLock) {
2686 logCallback("onEapFailure");
2687 mWifiMonitor.broadcastAuthenticationFailureEvent(
2688 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, -1);
2689 }
2690 }
2691
2692 @Override
2693 public void onWpsEventSuccess() {
2694 logCallback("onWpsEventSuccess");
2695 synchronized (mLock) {
2696 mWifiMonitor.broadcastWpsSuccessEvent(mIfaceName);
2697 }
2698 }
2699
2700 @Override
2701 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
2702 synchronized (mLock) {
2703 logCallback("onWpsEventFail");
2704 if (configError == WpsConfigError.MSG_TIMEOUT
2705 && errorInd == WpsErrorIndication.NO_ERROR) {
2706 mWifiMonitor.broadcastWpsTimeoutEvent(mIfaceName);
2707 } else {
2708 mWifiMonitor.broadcastWpsFailEvent(mIfaceName, configError, errorInd);
2709 }
2710 }
2711 }
2712
2713 @Override
2714 public void onWpsEventPbcOverlap() {
2715 synchronized (mLock) {
2716 logCallback("onWpsEventPbcOverlap");
2717 mWifiMonitor.broadcastWpsOverlapEvent(mIfaceName);
2718 }
2719 }
2720
2721 @Override
2722 public void onExtRadioWorkStart(int id) {
2723 synchronized (mLock) {
2724 logCallback("onExtRadioWorkStart");
2725 }
2726 }
2727
2728 @Override
2729 public void onExtRadioWorkTimeout(int id) {
2730 synchronized (mLock) {
2731 logCallback("onExtRadioWorkTimeout");
2732 }
2733 }
2734 }
2735
2736 private class SupplicantStaIfaceHalCallbackV1_1 extends
2737 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback.Stub {
2738 private String mIfaceName;
2739 private SupplicantStaIfaceHalCallback mCallbackV1_0;
2740
2741 SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName,
2742 @NonNull SupplicantStaIfaceHalCallback callback) {
2743 mIfaceName = ifaceName;
2744 mCallbackV1_0 = callback;
2745 }
2746
2747 @Override
2748 public void onNetworkAdded(int id) {
2749 mCallbackV1_0.onNetworkAdded(id);
2750 }
2751
2752 @Override
2753 public void onNetworkRemoved(int id) {
2754 mCallbackV1_0.onNetworkRemoved(id);
2755 }
2756
2757 @Override
2758 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
2759 ArrayList<Byte> ssid) {
2760 mCallbackV1_0.onStateChanged(newState, bssid, id, ssid);
2761 }
2762
2763 @Override
2764 public void onAnqpQueryDone(byte[/* 6 */] bssid,
2765 ISupplicantStaIfaceCallback.AnqpData data,
2766 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
2767 mCallbackV1_0.onAnqpQueryDone(bssid, data, hs20Data);
2768 }
2769
2770 @Override
2771 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
2772 ArrayList<Byte> data) {
2773 mCallbackV1_0.onHs20IconQueryDone(bssid, fileName, data);
2774 }
2775
2776 @Override
2777 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid,
2778 byte osuMethod, String url) {
2779 mCallbackV1_0.onHs20SubscriptionRemediation(bssid, osuMethod, url);
2780 }
2781
2782 @Override
2783 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
2784 int reAuthDelayInSec, String url) {
2785 mCallbackV1_0.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url);
2786 }
2787
2788 @Override
2789 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated,
2790 int reasonCode) {
2791 mCallbackV1_0.onDisconnected(bssid, locallyGenerated, reasonCode);
2792 }
2793
2794 @Override
2795 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode,
2796 boolean timedOut) {
2797 mCallbackV1_0.onAssociationRejected(bssid, statusCode, timedOut);
2798 }
2799
2800 @Override
2801 public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
2802 mCallbackV1_0.onAuthenticationTimeout(bssid);
2803 }
2804
2805 @Override
2806 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) {
2807 mCallbackV1_0.onBssidChanged(reason, bssid);
2808 }
2809
2810 @Override
2811 public void onEapFailure() {
2812 mCallbackV1_0.onEapFailure();
2813 }
2814
2815 @Override
2816 public void onEapFailure_1_1(int code) {
2817 synchronized (mLock) {
2818 logCallback("onEapFailure_1_1");
2819 mWifiMonitor.broadcastAuthenticationFailureEvent(
2820 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, code);
2821 }
2822 }
2823
2824 @Override
2825 public void onWpsEventSuccess() {
2826 mCallbackV1_0.onWpsEventSuccess();
2827 }
2828
2829 @Override
2830 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
2831 mCallbackV1_0.onWpsEventFail(bssid, configError, errorInd);
2832 }
2833
2834 @Override
2835 public void onWpsEventPbcOverlap() {
2836 mCallbackV1_0.onWpsEventPbcOverlap();
2837 }
2838
2839 @Override
2840 public void onExtRadioWorkStart(int id) {
2841 mCallbackV1_0.onExtRadioWorkStart(id);
2842 }
2843
2844 @Override
2845 public void onExtRadioWorkTimeout(int id) {
2846 mCallbackV1_0.onExtRadioWorkTimeout(id);
2847 }
2848 }
2849
2850 private class SupplicantStaIfaceHalCallbackV1_2 extends
2851 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback.Stub {
2852 private SupplicantStaIfaceHalCallbackV1_1 mCallbackV1_1;
2853
2854 SupplicantStaIfaceHalCallbackV1_2(
2855 @NonNull SupplicantStaIfaceHalCallbackV1_1 callback) {
2856 mCallbackV1_1 = callback;
2857 }
2858
2859 @Override
2860 public void onNetworkAdded(int id) {
2861 mCallbackV1_1.onNetworkAdded(id);
2862 }
2863
2864 @Override
2865 public void onNetworkRemoved(int id) {
2866 mCallbackV1_1.onNetworkRemoved(id);
2867 }
2868
2869 @Override
2870 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
2871 ArrayList<Byte> ssid) {
2872 mCallbackV1_1.onStateChanged(newState, bssid, id, ssid);
2873 }
2874
2875 @Override
2876 public void onAnqpQueryDone(byte[/* 6 */] bssid,
2877 ISupplicantStaIfaceCallback.AnqpData data,
2878 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
2879 mCallbackV1_1.onAnqpQueryDone(bssid, data, hs20Data);
2880 }
2881
2882 @Override
2883 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
2884 ArrayList<Byte> data) {
2885 mCallbackV1_1.onHs20IconQueryDone(bssid, fileName, data);
2886 }
2887
2888 @Override
2889 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid,
2890 byte osuMethod, String url) {
2891 mCallbackV1_1.onHs20SubscriptionRemediation(bssid, osuMethod, url);
2892 }
2893
2894 @Override
2895 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
2896 int reAuthDelayInSec, String url) {
2897 mCallbackV1_1.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url);
2898 }
2899
2900 @Override
2901 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated,
2902 int reasonCode) {
2903 mCallbackV1_1.onDisconnected(bssid, locallyGenerated, reasonCode);
2904 }
2905
2906 @Override
2907 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode,
2908 boolean timedOut) {
2909 mCallbackV1_1.onAssociationRejected(bssid, statusCode, timedOut);
2910 }
2911
2912 @Override
2913 public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
2914 mCallbackV1_1.onAuthenticationTimeout(bssid);
2915 }
2916
2917 @Override
2918 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) {
2919 mCallbackV1_1.onBssidChanged(reason, bssid);
2920 }
2921
2922 @Override
2923 public void onEapFailure() {
2924 mCallbackV1_1.onEapFailure();
2925 }
2926
2927 @Override
2928 public void onEapFailure_1_1(int code) {
2929 mCallbackV1_1.onEapFailure_1_1(code);
2930 }
2931
2932 @Override
2933 public void onWpsEventSuccess() {
2934 mCallbackV1_1.onWpsEventSuccess();
2935 }
2936
2937 @Override
2938 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
2939 mCallbackV1_1.onWpsEventFail(bssid, configError, errorInd);
2940 }
2941
2942 @Override
2943 public void onWpsEventPbcOverlap() {
2944 mCallbackV1_1.onWpsEventPbcOverlap();
2945 }
2946
2947 @Override
2948 public void onExtRadioWorkStart(int id) {
2949 mCallbackV1_1.onExtRadioWorkStart(id);
2950 }
2951
2952 @Override
2953 public void onExtRadioWorkTimeout(int id) {
2954 mCallbackV1_1.onExtRadioWorkTimeout(id);
2955 }
2956
2957 @Override
2958 public void onDppSuccessConfigReceived(ArrayList<Byte> ssid, String password,
2959 byte[] psk, int securityAkm) {
2960 if (mDppCallback == null) {
2961 loge("onDppSuccessConfigReceived callback is null");
2962 return;
2963 }
2964
2965 WifiConfiguration newWifiConfiguration = new WifiConfiguration();
2966
2967 // Set up SSID
2968 WifiSsid wifiSsid =
2969 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
2970
2971 newWifiConfiguration.SSID = "\"" + wifiSsid.toString() + "\"";
2972
2973 // Set up password or PSK
2974 if (password != null) {
2975 newWifiConfiguration.preSharedKey = "\"" + password + "\"";
2976 } else if (psk != null) {
2977 newWifiConfiguration.preSharedKey = psk.toString();
2978 }
2979
2980 // Set up key management: SAE or PSK
2981 if (securityAkm == DppAkm.SAE || securityAkm == DppAkm.PSK_SAE) {
2982 newWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
2983 newWifiConfiguration.requirePMF = true;
2984 } else if (securityAkm == DppAkm.PSK) {
2985 newWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
2986 } else {
2987 // No other AKMs are currently supported
2988 onDppFailure(DppFailureCode.NOT_SUPPORTED);
2989 return;
2990 }
2991
2992 // Set up default values
2993 newWifiConfiguration.creatorName = mContext.getPackageManager()
2994 .getNameForUid(Process.WIFI_UID);
2995 newWifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
2996 newWifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
2997 newWifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
2998 newWifiConfiguration.status = WifiConfiguration.Status.ENABLED;
2999
3000 mDppCallback.onSuccessConfigReceived(newWifiConfiguration);
3001 }
3002
3003 @Override
3004 public void onDppSuccessConfigSent() {
3005 if (mDppCallback != null) {
3006 mDppCallback.onSuccessConfigSent();
3007 } else {
3008 loge("onSuccessConfigSent callback is null");
3009 }
3010 }
3011
3012 @Override
3013 public void onDppProgress(int code) {
3014 if (mDppCallback != null) {
3015 mDppCallback.onProgress(code);
3016 } else {
3017 loge("onDppProgress callback is null");
3018 }
3019 }
3020
3021 @Override
3022 public void onDppFailure(int code) {
3023 if (mDppCallback != null) {
3024 mDppCallback.onFailure(code);
3025 } else {
3026 loge("onDppFailure callback is null");
3027 }
3028 }
3029 }
3030
3031 private static void logd(String s) {
3032 Log.d(TAG, s);
3033 }
3034
3035 private static void logi(String s) {
3036 Log.i(TAG, s);
3037 }
3038
3039 private static void loge(String s) {
3040 Log.e(TAG, s);
3041 }
3042
3043 /**
3044 * Returns a bitmask of advanced key management capabilities: WPA3 SAE/SUITE B and OWE
3045 * Bitmask used is:
3046 * - WIFI_FEATURE_WPA3_SAE
3047 * - WIFI_FEATURE_WPA3_SUITE_B
3048 * - WIFI_FEATURE_OWE
3049 *
3050 * This is a v1.2+ HAL feature.
3051 * On error, or if these features are not supported, 0 is returned.
3052 */
3053 public int getAdvancedKeyMgmtCapabilities(@NonNull String ifaceName) {
3054 final String methodStr = "getAdvancedKeyMgmtCapabilities";
3055
3056 int advancedCapabilities = 0;
3057 int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName);
3058
3059 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork
3060 .KeyMgmtMask.SAE) != 0) {
3061 advancedCapabilities |= WIFI_FEATURE_WPA3_SAE;
3062
3063 if (mVerboseLoggingEnabled) {
3064 Log.v(TAG, methodStr + ": SAE supported");
3065 }
3066 }
3067
3068 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork
3069 .KeyMgmtMask.SUITE_B_192) != 0) {
3070 advancedCapabilities |= WIFI_FEATURE_WPA3_SUITE_B;
3071
3072 if (mVerboseLoggingEnabled) {
3073 Log.v(TAG, methodStr + ": SUITE_B supported");
3074 }
3075 }
3076
3077 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork
3078 .KeyMgmtMask.OWE) != 0) {
3079 advancedCapabilities |= WIFI_FEATURE_OWE;
3080
3081 if (mVerboseLoggingEnabled) {
3082 Log.v(TAG, methodStr + ": OWE supported");
3083 }
3084 }
3085
3086 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork
3087 .KeyMgmtMask.DPP) != 0) {
3088 advancedCapabilities |= WIFI_FEATURE_DPP;
3089
3090 if (mVerboseLoggingEnabled) {
3091 Log.v(TAG, methodStr + ": DPP supported");
3092 }
3093 }
3094
3095 if (mVerboseLoggingEnabled) {
3096 Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities);
3097 }
3098
3099 return advancedCapabilities;
3100 }
3101
3102 private int getKeyMgmtCapabilities(@NonNull String ifaceName) {
3103 final String methodStr = "getKeyMgmtCapabilities";
3104 MutableBoolean status = new MutableBoolean(false);
3105 MutableInt keyMgmtMask = new MutableInt(0);
3106
3107 if (isV1_2()) {
3108 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3109 if (iface == null) {
3110 return 0;
3111 }
3112
3113 // Get a v1.2 supplicant STA Interface
3114 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3115 getStaIfaceMockableV1_2(iface);
3116
3117 if (staIfaceV12 == null) {
3118 Log.e(TAG, methodStr
3119 + ": ISupplicantStaIface is null, cannot get advanced capabilities");
3120 return 0;
3121 }
3122
3123 try {
3124 // Support for new key management types; SAE, SUITE_B, OWE
3125 // Requires HAL v1.2 or higher
3126 staIfaceV12.getKeyMgmtCapabilities(
3127 (SupplicantStatus statusInternal, int keyMgmtMaskInternal) -> {
3128 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS;
3129 if (status.value) {
3130 keyMgmtMask.value = keyMgmtMaskInternal;
3131 }
3132 checkStatusAndLogFailure(statusInternal, methodStr);
3133 });
3134 } catch (RemoteException e) {
3135 handleRemoteException(e, methodStr);
3136 }
3137 } else {
3138 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL");
3139 }
3140
3141 // 0 is returned in case of an error
3142 return keyMgmtMask.value;
3143 }
3144
3145 /**
3146 * Adds a DPP peer URI to the URI list.
3147 *
3148 * This is a v1.2+ HAL feature.
3149 * Returns an ID to be used later to refer to this URI (>0).
3150 * On error, or if these features are not supported, -1 is returned.
3151 */
3152 public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
3153 final String methodStr = "addDppPeerUri";
3154 MutableBoolean status = new MutableBoolean(false);
3155 MutableInt bootstrapId = new MutableInt(-1);
3156
3157 if (!isV1_2()) {
3158 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL");
3159 return -1;
3160 }
3161
3162 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3163 if (iface == null) {
3164 return -1;
3165 }
3166
3167 // Get a v1.2 supplicant STA Interface
3168 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3169 getStaIfaceMockableV1_2(iface);
3170
3171 if (staIfaceV12 == null) {
3172 Log.e(TAG, methodStr + ": ISupplicantStaIface is null");
3173 return -1;
3174 }
3175
3176 try {
3177 // Support for DPP (Easy connect)
3178 // Requires HAL v1.2 or higher
3179 staIfaceV12.addDppPeerUri(uri,
3180 (SupplicantStatus statusInternal, int bootstrapIdInternal) -> {
3181 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS;
3182 if (status.value) {
3183 bootstrapId.value = bootstrapIdInternal;
3184 }
3185 checkStatusAndLogFailure(statusInternal, methodStr);
3186 });
3187 } catch (RemoteException e) {
3188 handleRemoteException(e, methodStr);
3189 return -1;
3190 }
3191
3192 return bootstrapId.value;
3193 }
3194
3195 /**
3196 * Removes a DPP URI to the URI list given an ID.
3197 *
3198 * This is a v1.2+ HAL feature.
3199 * Returns true when operation is successful
3200 * On error, or if these features are not supported, false is returned.
3201 */
3202 public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) {
3203 final String methodStr = "removeDppUri";
3204
3205 if (!isV1_2()) {
3206 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL");
3207 return false;
3208 }
3209
3210 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3211 if (iface == null) {
3212 return false;
3213 }
3214
3215 // Get a v1.2 supplicant STA Interface
3216 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3217 getStaIfaceMockableV1_2(iface);
3218
3219 if (staIfaceV12 == null) {
3220 Log.e(TAG, methodStr + ": ISupplicantStaIface is null");
3221 return false;
3222 }
3223
3224 try {
3225 // Support for DPP (Easy connect)
3226 // Requires HAL v1.2 or higher
3227 SupplicantStatus status = staIfaceV12.removeDppUri(bootstrapId);
3228 return checkStatusAndLogFailure(status, methodStr);
3229 } catch (RemoteException e) {
3230 handleRemoteException(e, methodStr);
3231 }
3232
3233 return false;
3234 }
3235
3236 /**
3237 * Stops/aborts DPP Initiator request
3238 *
3239 * This is a v1.2+ HAL feature.
3240 * Returns true when operation is successful
3241 * On error, or if these features are not supported, false is returned.
3242 */
3243 public boolean stopDppInitiator(@NonNull String ifaceName) {
3244 final String methodStr = "stopDppInitiator";
3245
3246 if (!isV1_2()) {
3247 return false;
3248 }
3249
3250 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3251 if (iface == null) {
3252 return false;
3253 }
3254
3255 // Get a v1.2 supplicant STA Interface
3256 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3257 getStaIfaceMockableV1_2(iface);
3258
3259 if (staIfaceV12 == null) {
3260 Log.e(TAG, methodStr + ": ISupplicantStaIface is null");
3261 return false;
3262 }
3263
3264 try {
3265 // Support for DPP (Easy connect)
3266 // Requires HAL v1.2 or higher
3267 SupplicantStatus status = staIfaceV12.stopDppInitiator();
3268 return checkStatusAndLogFailure(status, methodStr);
3269 } catch (RemoteException e) {
3270 handleRemoteException(e, methodStr);
3271 }
3272
3273 return false;
3274 }
3275
3276 /**
3277 * Starts DPP Configurator-Initiator request
3278 *
3279 * This is a v1.2+ HAL feature.
3280 * Returns true when operation is successful
3281 * On error, or if these features are not supported, false is returned.
3282 */
3283 public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
3284 int ownBootstrapId, @NonNull String ssid, String password, String psk,
3285 int netRole, int securityAkm) {
3286 final String methodStr = "startDppConfiguratorInitiator";
3287
3288 if (!isV1_2()) {
3289 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL");
3290 return false;
3291 }
3292
3293 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3294 if (iface == null) {
3295 return false;
3296 }
3297
3298 // Get a v1.2 supplicant STA Interface
3299 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3300 getStaIfaceMockableV1_2(iface);
3301
3302 if (staIfaceV12 == null) {
3303 Log.e(TAG, methodStr + ": ISupplicantStaIface is null");
3304 return false;
3305 }
3306
3307 try {
3308 // Support for DPP (Easy connect)
3309 // Requires HAL v1.2 or higher
3310 SupplicantStatus status = staIfaceV12.startDppConfiguratorInitiator(peerBootstrapId,
3311 ownBootstrapId, ssid, password != null ? password : "", psk != null ? psk : "",
3312 netRole, securityAkm);
3313 return checkStatusAndLogFailure(status, methodStr);
3314 } catch (RemoteException e) {
3315 handleRemoteException(e, methodStr);
3316 }
3317
3318 return false;
3319 }
3320
3321 /**
3322 * Starts DPP Enrollee-Initiator request
3323 *
3324 * This is a v1.2+ HAL feature.
3325 * Returns true when operation is successful
3326 * On error, or if these features are not supported, false is returned.
3327 */
3328 public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
3329 int ownBootstrapId) {
3330 final String methodStr = "startDppEnrolleeInitiator";
3331
3332 if (!isV1_2()) {
3333 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL");
3334 return false;
3335 }
3336
3337 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
3338 if (iface == null) {
3339 return false;
3340 }
3341
3342 // Get a v1.2 supplicant STA Interface
3343 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 =
3344 getStaIfaceMockableV1_2(iface);
3345
3346 if (staIfaceV12 == null) {
3347 Log.e(TAG, methodStr + ": ISupplicantStaIface is null");
3348 return false;
3349 }
3350
3351 try {
3352 // Support for DPP (Easy connect)
3353 // Requires HAL v1.2 or higher
3354 SupplicantStatus status = staIfaceV12.startDppEnrolleeInitiator(peerBootstrapId,
3355 ownBootstrapId);
3356 return checkStatusAndLogFailure(status, methodStr);
3357 } catch (RemoteException e) {
3358 handleRemoteException(e, methodStr);
3359 }
3360
3361 return false;
3362 }
3363
3364 /**
3365 * Register callbacks for DPP events.
3366 *
3367 * @param dppCallback DPP callback object.
3368 */
3369 public void registerDppCallback(DppEventCallback dppCallback) {
3370 mDppCallback = dppCallback;
3371 }
3372}