1 /* 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 */ 16 package com.android.server.wifi; 17 18 import android.annotation.NonNull; 19 import android.content.Context; 20 import android.hardware.wifi.hostapd.V1_0.HostapdStatus; 21 import android.hardware.wifi.hostapd.V1_0.HostapdStatusCode; 22 import android.hardware.wifi.hostapd.V1_0.IHostapd; 23 import android.hardware.wifi.hostapd.V1_2.DebugLevel; 24 import android.hardware.wifi.hostapd.V1_2.Ieee80211ReasonCode; 25 import android.hardware.wifi.hostapd.V1_3.Bandwidth; 26 import android.hardware.wifi.hostapd.V1_3.Generation; 27 import android.hidl.manager.V1_0.IServiceManager; 28 import android.hidl.manager.V1_0.IServiceNotification; 29 import android.net.MacAddress; 30 import android.net.wifi.ScanResult; 31 import android.net.wifi.SoftApConfiguration; 32 import android.net.wifi.SoftApConfiguration.BandType; 33 import android.net.wifi.SoftApInfo; 34 import android.net.wifi.WifiManager; 35 import android.os.Handler; 36 import android.os.IHwBinder.DeathRecipient; 37 import android.os.RemoteException; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.modules.utils.build.SdkLevel; 43 import com.android.server.wifi.WifiNative.HostapdDeathEventHandler; 44 import com.android.server.wifi.WifiNative.SoftApListener; 45 import com.android.server.wifi.util.ApConfigUtil; 46 import com.android.server.wifi.util.NativeUtil; 47 import com.android.wifi.resources.R; 48 49 import java.util.ArrayList; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.NoSuchElementException; 53 import java.util.Random; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 57 import javax.annotation.concurrent.ThreadSafe; 58 59 /** 60 * To maintain thread-safety, the locking protocol is that every non-static method (regardless of 61 * access level) acquires mLock. 62 */ 63 @ThreadSafe 64 public class HostapdHal { 65 private static final String TAG = "HostapdHal"; 66 @VisibleForTesting 67 public static final String HAL_INSTANCE_NAME = "default"; 68 @VisibleForTesting 69 public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L; 70 71 private final Object mLock = new Object(); 72 private boolean mVerboseLoggingEnabled = false; 73 private final Context mContext; 74 private final Handler mEventHandler; 75 76 // Hostapd HAL interface objects 77 private IServiceManager mIServiceManager = null; 78 private IHostapd mIHostapd; 79 private HashMap<String, Runnable> mSoftApFailureListeners = new HashMap<>(); 80 private SoftApListener mSoftApEventListener; 81 private HostapdDeathEventHandler mDeathEventHandler; 82 private ServiceManagerDeathRecipient mServiceManagerDeathRecipient; 83 private HostapdDeathRecipient mHostapdDeathRecipient; 84 // Death recipient cookie registered for current supplicant instance. 85 private long mDeathRecipientCookie = 0; 86 87 private final IServiceNotification mServiceNotificationCallback = 88 new IServiceNotification.Stub() { 89 public void onRegistration(String fqName, String name, boolean preexisting) { 90 synchronized (mLock) { 91 if (mVerboseLoggingEnabled) { 92 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 93 + ", " + name + " preexisting=" + preexisting); 94 } 95 if (!initHostapdService()) { 96 Log.e(TAG, "initalizing IHostapd failed."); 97 hostapdServiceDiedHandler(mDeathRecipientCookie); 98 } else { 99 Log.i(TAG, "Completed initialization of IHostapd."); 100 } 101 } 102 } 103 }; 104 private class ServiceManagerDeathRecipient implements DeathRecipient { 105 @Override serviceDied(long cookie)106 public void serviceDied(long cookie) { 107 mEventHandler.post(() -> { 108 synchronized (mLock) { 109 Log.w(TAG, "IServiceManager died: cookie=" + cookie); 110 hostapdServiceDiedHandler(mDeathRecipientCookie); 111 mIServiceManager = null; // Will need to register a new ServiceNotification 112 } 113 }); 114 } 115 } 116 private class HostapdDeathRecipient implements DeathRecipient { 117 @Override serviceDied(long cookie)118 public void serviceDied(long cookie) { 119 mEventHandler.post(() -> { 120 synchronized (mLock) { 121 Log.w(TAG, "IHostapd/IHostapd died: cookie=" + cookie); 122 hostapdServiceDiedHandler(cookie); 123 } 124 }); 125 } 126 } 127 HostapdHal(Context context, Handler handler)128 public HostapdHal(Context context, Handler handler) { 129 mContext = context; 130 mEventHandler = handler; 131 mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient(); 132 mHostapdDeathRecipient = new HostapdDeathRecipient(); 133 } 134 135 /** 136 * Enable/Disable verbose logging. 137 * 138 * @param enable true to enable, false to disable. 139 */ enableVerboseLogging(boolean enable)140 void enableVerboseLogging(boolean enable) { 141 synchronized (mLock) { 142 mVerboseLoggingEnabled = enable; 143 setLogLevel(); 144 } 145 } 146 147 /** 148 * Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for 149 * the device. 150 * @return true if supported, false otherwise. 151 */ isV1_1()152 private boolean isV1_1() { 153 return checkHalVersionByInterfaceName( 154 android.hardware.wifi.hostapd.V1_1.IHostapd.kInterfaceName); 155 } 156 157 /** 158 * Uses the IServiceManager to check if the device is running V1_2 of the HAL from the VINTF for 159 * the device. 160 * @return true if supported, false otherwise. 161 */ isV1_2()162 private boolean isV1_2() { 163 return checkHalVersionByInterfaceName( 164 android.hardware.wifi.hostapd.V1_2.IHostapd.kInterfaceName); 165 } 166 167 /** 168 * Uses the IServiceManager to check if the device is running V1_3 of the HAL from the VINTF for 169 * the device. 170 * @return true if supported, false otherwise. 171 */ isV1_3()172 private boolean isV1_3() { 173 return checkHalVersionByInterfaceName( 174 android.hardware.wifi.hostapd.V1_3.IHostapd.kInterfaceName); 175 } 176 checkHalVersionByInterfaceName(String interfaceName)177 private boolean checkHalVersionByInterfaceName(String interfaceName) { 178 if (interfaceName == null) { 179 return false; 180 } 181 synchronized (mLock) { 182 if (mIServiceManager == null) { 183 Log.e(TAG, "checkHalVersionByInterfaceName called but mServiceManager is null!?"); 184 return false; 185 } 186 try { 187 return (mIServiceManager.getTransport( 188 interfaceName, 189 HAL_INSTANCE_NAME) 190 != IServiceManager.Transport.EMPTY); 191 } catch (RemoteException e) { 192 Log.e(TAG, "Exception while operating on IServiceManager: " + e); 193 handleRemoteException(e, "getTransport"); 194 return false; 195 } 196 } 197 } 198 199 /** 200 * Link to death for IServiceManager object. 201 * @return true on success, false otherwise. 202 */ linkToServiceManagerDeath()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 hostapdServiceDiedHandler(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 mIServiceManager = null; // Will need to register a new ServiceNotification 216 return false; 217 } 218 return true; 219 } 220 } 221 222 /** 223 * Returns whether or not the hostapd supported to get the AP info from the callback. 224 */ isApInfoCallbackSupported()225 public boolean isApInfoCallbackSupported() { 226 return isV1_3(); 227 } 228 229 /** 230 * Registers a service notification for the IHostapd service, which triggers intialization of 231 * the IHostapd 232 * @return true if the service notification was successfully registered 233 */ initialize()234 public boolean initialize() { 235 synchronized (mLock) { 236 if (mVerboseLoggingEnabled) { 237 Log.i(TAG, "Registering IHostapd service ready callback."); 238 } 239 mIHostapd = null; 240 if (mIServiceManager != null) { 241 // Already have an IServiceManager and serviceNotification registered, don't 242 // don't register another. 243 return true; 244 } 245 try { 246 mIServiceManager = getServiceManagerMockable(); 247 if (mIServiceManager == null) { 248 Log.e(TAG, "Failed to get HIDL Service Manager"); 249 return false; 250 } 251 if (!linkToServiceManagerDeath()) { 252 return false; 253 } 254 /* TODO(b/33639391) : Use the new IHostapd.registerForNotifications() once it 255 exists */ 256 if (!mIServiceManager.registerForNotifications( 257 IHostapd.kInterfaceName, "", mServiceNotificationCallback)) { 258 Log.e(TAG, "Failed to register for notifications to " 259 + IHostapd.kInterfaceName); 260 mIServiceManager = null; // Will need to register a new ServiceNotification 261 return false; 262 } 263 } catch (RemoteException e) { 264 Log.e(TAG, "Exception while trying to register a listener for IHostapd service: " 265 + e); 266 hostapdServiceDiedHandler(mDeathRecipientCookie); 267 mIServiceManager = null; // Will need to register a new ServiceNotification 268 return false; 269 } 270 return true; 271 } 272 } 273 274 /** 275 * Link to death for IHostapd object. 276 * @return true on success, false otherwise. 277 */ linkToHostapdDeath(DeathRecipient deathRecipient, long cookie)278 private boolean linkToHostapdDeath(DeathRecipient deathRecipient, long cookie) { 279 synchronized (mLock) { 280 if (mIHostapd == null) return false; 281 try { 282 if (!mIHostapd.linkToDeath(deathRecipient, cookie)) { 283 Log.wtf(TAG, "Error on linkToDeath on IHostapd"); 284 hostapdServiceDiedHandler(mDeathRecipientCookie); 285 return false; 286 } 287 } catch (RemoteException e) { 288 Log.e(TAG, "IHostapd.linkToDeath exception", e); 289 return false; 290 } 291 return true; 292 } 293 } 294 registerCallback( android.hardware.wifi.hostapd.V1_1.IHostapdCallback callback)295 private boolean registerCallback( 296 android.hardware.wifi.hostapd.V1_1.IHostapdCallback callback) { 297 synchronized (mLock) { 298 String methodStr = "registerCallback_1_1"; 299 try { 300 android.hardware.wifi.hostapd.V1_1.IHostapd iHostapdV1_1 = getHostapdMockableV1_1(); 301 if (iHostapdV1_1 == null) return false; 302 HostapdStatus status = iHostapdV1_1.registerCallback(callback); 303 return checkStatusAndLogFailure(status, methodStr); 304 } catch (RemoteException e) { 305 handleRemoteException(e, methodStr); 306 return false; 307 } 308 } 309 } 310 registerCallback_1_3( android.hardware.wifi.hostapd.V1_3.IHostapdCallback callback)311 private boolean registerCallback_1_3( 312 android.hardware.wifi.hostapd.V1_3.IHostapdCallback callback) { 313 synchronized (mLock) { 314 String methodStr = "registerCallback_1_3"; 315 try { 316 android.hardware.wifi.hostapd.V1_3.IHostapd iHostapdV1_3 = getHostapdMockableV1_3(); 317 if (iHostapdV1_3 == null) return false; 318 android.hardware.wifi.hostapd.V1_2.HostapdStatus status = 319 iHostapdV1_3.registerCallback_1_3(callback); 320 return checkStatusAndLogFailure12(status, methodStr); 321 } catch (RemoteException e) { 322 handleRemoteException(e, methodStr); 323 return false; 324 } 325 } 326 } 327 328 /** 329 * Initialize the IHostapd object. 330 * @return true on success, false otherwise. 331 */ initHostapdService()332 private boolean initHostapdService() { 333 synchronized (mLock) { 334 try { 335 mIHostapd = getHostapdMockable(); 336 } catch (RemoteException e) { 337 Log.e(TAG, "IHostapd.getService exception: " + e); 338 return false; 339 } catch (NoSuchElementException e) { 340 Log.e(TAG, "IHostapd.getService exception: " + e); 341 return false; 342 } 343 if (mIHostapd == null) { 344 Log.e(TAG, "Got null IHostapd service. Stopping hostapd HIDL startup"); 345 return false; 346 } 347 if (!linkToHostapdDeath(mHostapdDeathRecipient, ++mDeathRecipientCookie)) { 348 Log.e(TAG, "Fail to link to Hostapd Death, Stopping hostapd HIDL startup"); 349 mIHostapd = null; 350 return false; 351 } 352 // Register for callbacks for 1.1 hostapd. 353 if (isV1_3()) { 354 if (!registerCallback_1_3(new HostapdCallback_1_3())) { 355 Log.e(TAG, "Fail to regiester Callback 1_3, Stopping hostapd HIDL startup"); 356 mIHostapd = null; 357 return false; 358 } 359 } else if (isV1_1() && !registerCallback(new HostapdCallback())) { 360 Log.e(TAG, "Fail to regiester Callback, Stopping hostapd HIDL startup"); 361 mIHostapd = null; 362 return false; 363 } 364 365 // Setup log level 366 setLogLevel(); 367 } 368 return true; 369 } 370 371 /** 372 * Register the provided callback handler for SoftAp events. 373 * <p> 374 * Note that only one callback can be registered at a time - any registration overrides previous 375 * registrations. 376 * 377 * @param ifaceName Name of the interface. 378 * @param listener Callback listener for AP events. 379 * @return true on success, false on failure. 380 */ registerApCallback(@onNull String ifaceName, @NonNull SoftApListener listener)381 public boolean registerApCallback(@NonNull String ifaceName, 382 @NonNull SoftApListener listener) { 383 if (listener == null) { 384 Log.e(TAG, "registerApCallback called with a null callback"); 385 return false; 386 } 387 388 if (!isV1_3()) { 389 Log.d(TAG, "The current HAL doesn't support event callback."); 390 return false; 391 } 392 mSoftApEventListener = listener; 393 Log.i(TAG, "registerApCallback Successful in " + ifaceName); 394 return true; 395 } 396 397 /** 398 * Add and start a new access point. 399 * 400 * @param ifaceName Name of the interface. 401 * @param config Configuration to use for the AP. 402 * @param isMetered Indicates the network is metered or not. 403 * @param onFailureListener A runnable to be triggered on failure. 404 * @return true on success, false otherwise. 405 */ addAccessPoint(@onNull String ifaceName, @NonNull SoftApConfiguration config, boolean isMetered, @NonNull Runnable onFailureListener)406 public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config, 407 boolean isMetered, @NonNull Runnable onFailureListener) { 408 synchronized (mLock) { 409 final String methodStr = "addAccessPoint"; 410 IHostapd.IfaceParams ifaceParamsV1_0 = prepareIfaceParamsV1_0(ifaceName, config); 411 android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams nwParamsV1_2 = 412 prepareNetworkParamsV1_2(config); 413 if (nwParamsV1_2 == null) return false; 414 if (!checkHostapdAndLogFailure(methodStr)) return false; 415 try { 416 HostapdStatus status; 417 if (!isV1_1()) { 418 // V1_0 case 419 status = mIHostapd.addAccessPoint(ifaceParamsV1_0, nwParamsV1_2.V1_0); 420 if (!checkStatusAndLogFailure(status, methodStr)) { 421 return false; 422 } 423 } else { 424 android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParamsV1_1 = 425 prepareIfaceParamsV1_1(ifaceParamsV1_0, config); 426 if (!isV1_2()) { 427 // V1_1 case 428 android.hardware.wifi.hostapd.V1_1.IHostapd iHostapdV1_1 = 429 getHostapdMockableV1_1(); 430 if (iHostapdV1_1 == null) return false; 431 status = iHostapdV1_1.addAccessPoint_1_1(ifaceParamsV1_1, 432 nwParamsV1_2.V1_0); 433 if (!checkStatusAndLogFailure(status, methodStr)) { 434 return false; 435 } 436 } else { 437 // V1_2 & V1_3 case 438 android.hardware.wifi.hostapd.V1_2.HostapdStatus status12; 439 android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParamsV1_2 = 440 prepareIfaceParamsV1_2(ifaceParamsV1_1, config); 441 if (!isV1_3()) { 442 // V1_2 case 443 android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 = 444 getHostapdMockableV1_2(); 445 if (iHostapdV1_2 == null) return false; 446 status12 = iHostapdV1_2.addAccessPoint_1_2(ifaceParamsV1_2, 447 nwParamsV1_2); 448 } else { 449 // V1_3 case 450 android.hardware.wifi.hostapd.V1_3 451 .IHostapd.NetworkParams nwParamsV1_3 = 452 new android.hardware.wifi.hostapd.V1_3 453 .IHostapd.NetworkParams(); 454 nwParamsV1_3.V1_2 = nwParamsV1_2; 455 nwParamsV1_3.isMetered = isMetered; 456 android.hardware.wifi.hostapd.V1_3.IHostapd.IfaceParams ifaceParams1_3 = 457 prepareIfaceParamsV1_3(ifaceParamsV1_2, config); 458 android.hardware.wifi.hostapd.V1_3.IHostapd iHostapdV1_3 = 459 getHostapdMockableV1_3(); 460 if (iHostapdV1_3 == null) return false; 461 status12 = iHostapdV1_3.addAccessPoint_1_3(ifaceParams1_3, 462 nwParamsV1_3); 463 } 464 if (!checkStatusAndLogFailure12(status12, methodStr)) { 465 return false; 466 } 467 } 468 } 469 470 mSoftApFailureListeners.put(ifaceName, onFailureListener); 471 return true; 472 } catch (IllegalArgumentException e) { 473 Log.e(TAG, "Unrecognized apBand: " + config.getBand()); 474 return false; 475 } catch (RemoteException e) { 476 handleRemoteException(e, methodStr); 477 return false; 478 } 479 } 480 } 481 482 /** 483 * Remove a previously started access point. 484 * 485 * @param ifaceName Name of the interface. 486 * @return true on success, false otherwise. 487 */ removeAccessPoint(@onNull String ifaceName)488 public boolean removeAccessPoint(@NonNull String ifaceName) { 489 synchronized (mLock) { 490 final String methodStr = "removeAccessPoint"; 491 if (!checkHostapdAndLogFailure(methodStr)) return false; 492 try { 493 HostapdStatus status = mIHostapd.removeAccessPoint(ifaceName); 494 if (!checkStatusAndLogFailure(status, methodStr)) { 495 return false; 496 } 497 mSoftApFailureListeners.remove(ifaceName); 498 mSoftApEventListener = null; 499 return true; 500 } catch (RemoteException e) { 501 handleRemoteException(e, methodStr); 502 return false; 503 } 504 } 505 } 506 507 /** 508 * Remove a previously connected client. 509 * 510 * @param ifaceName Name of the interface. 511 * @param client Mac Address of the client. 512 * @param reasonCode One of disconnect reason code which defined in {@link WifiManager}. 513 * @return true on success, false otherwise. 514 */ forceClientDisconnect(@onNull String ifaceName, @NonNull MacAddress client, int reasonCode)515 public boolean forceClientDisconnect(@NonNull String ifaceName, 516 @NonNull MacAddress client, int reasonCode) { 517 final String methodStr = "forceClientDisconnect"; 518 if (isV1_2()) { 519 try { 520 android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 = 521 getHostapdMockableV1_2(); 522 if (iHostapdV1_2 == null) return false; 523 byte[] clientMacByteArray = client.toByteArray(); 524 short disconnectReason; 525 switch (reasonCode) { 526 case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER: 527 disconnectReason = Ieee80211ReasonCode.WLAN_REASON_PREV_AUTH_NOT_VALID; 528 break; 529 case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS: 530 disconnectReason = Ieee80211ReasonCode.WLAN_REASON_DISASSOC_AP_BUSY; 531 break; 532 case WifiManager.SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED: 533 disconnectReason = Ieee80211ReasonCode.WLAN_REASON_UNSPECIFIED; 534 break; 535 default: 536 throw new IllegalArgumentException( 537 "Unknown disconnect reason code:" + reasonCode); 538 } 539 android.hardware.wifi.hostapd.V1_2.HostapdStatus status = 540 iHostapdV1_2.forceClientDisconnect(ifaceName, 541 clientMacByteArray, disconnectReason); 542 if (status.code == HostapdStatusCode.SUCCESS) { 543 return true; 544 } 545 Log.d(TAG, "Error when call forceClientDisconnect, status.code = " + status.code); 546 } catch (RemoteException e) { 547 handleRemoteException(e, methodStr); 548 } 549 } else { 550 Log.d(TAG, "HIDL doesn't support forceClientDisconnect"); 551 } 552 return false; 553 } 554 555 /** 556 * Registers a death notification for hostapd. 557 * @return Returns true on success. 558 */ registerDeathHandler(@onNull HostapdDeathEventHandler handler)559 public boolean registerDeathHandler(@NonNull HostapdDeathEventHandler handler) { 560 if (mDeathEventHandler != null) { 561 Log.e(TAG, "Death handler already present"); 562 } 563 mDeathEventHandler = handler; 564 return true; 565 } 566 567 /** 568 * Deregisters a death notification for hostapd. 569 * @return Returns true on success. 570 */ deregisterDeathHandler()571 public boolean deregisterDeathHandler() { 572 if (mDeathEventHandler == null) { 573 Log.e(TAG, "No Death handler present"); 574 } 575 mDeathEventHandler = null; 576 return true; 577 } 578 579 /** 580 * Clear internal state. 581 */ clearState()582 private void clearState() { 583 synchronized (mLock) { 584 mIHostapd = null; 585 } 586 } 587 588 /** 589 * Handle hostapd death. 590 */ hostapdServiceDiedHandler(long cookie)591 private void hostapdServiceDiedHandler(long cookie) { 592 synchronized (mLock) { 593 if (mDeathRecipientCookie != cookie) { 594 Log.i(TAG, "Ignoring stale death recipient notification"); 595 return; 596 } 597 clearState(); 598 if (mDeathEventHandler != null) { 599 mDeathEventHandler.onDeath(); 600 } 601 } 602 } 603 604 /** 605 * Signals whether Initialization completed successfully. 606 */ isInitializationStarted()607 public boolean isInitializationStarted() { 608 synchronized (mLock) { 609 return mIServiceManager != null; 610 } 611 } 612 613 /** 614 * Signals whether Initialization completed successfully. 615 */ isInitializationComplete()616 public boolean isInitializationComplete() { 617 synchronized (mLock) { 618 return mIHostapd != null; 619 } 620 } 621 622 /** 623 * Start the hostapd daemon. 624 * 625 * @return true on success, false otherwise. 626 */ startDaemon()627 public boolean startDaemon() { 628 synchronized (mLock) { 629 try { 630 // This should startup hostapd daemon using the lazy start HAL mechanism. 631 getHostapdMockable(); 632 } catch (RemoteException e) { 633 Log.e(TAG, "Exception while trying to start hostapd: " 634 + e); 635 hostapdServiceDiedHandler(mDeathRecipientCookie); 636 return false; 637 } catch (NoSuchElementException e) { 638 // We're starting the daemon, so expect |NoSuchElementException|. 639 Log.d(TAG, "Successfully triggered start of hostapd using HIDL"); 640 } 641 return true; 642 } 643 } 644 645 /** 646 * Terminate the hostapd daemon & wait for it's death. 647 */ terminate()648 public void terminate() { 649 synchronized (mLock) { 650 // Register for a new death listener to block until hostapd is dead. 651 final long waitForDeathCookie = new Random().nextLong(); 652 final CountDownLatch waitForDeathLatch = new CountDownLatch(1); 653 linkToHostapdDeath((cookie) -> { 654 Log.d(TAG, "IHostapd died: cookie=" + cookie); 655 if (cookie != waitForDeathCookie) return; 656 waitForDeathLatch.countDown(); 657 }, waitForDeathCookie); 658 659 final String methodStr = "terminate"; 660 if (!checkHostapdAndLogFailure(methodStr)) return; 661 try { 662 mIHostapd.terminate(); 663 } catch (RemoteException e) { 664 handleRemoteException(e, methodStr); 665 } 666 667 // Now wait for death listener callback to confirm that it's dead. 668 try { 669 if (!waitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 670 Log.w(TAG, "Timed out waiting for confirmation of hostapd death"); 671 } 672 } catch (InterruptedException e) { 673 Log.w(TAG, "Failed to wait for hostapd death"); 674 } 675 } 676 } 677 678 /** 679 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 680 */ 681 @VisibleForTesting getServiceManagerMockable()682 protected IServiceManager getServiceManagerMockable() throws RemoteException { 683 synchronized (mLock) { 684 return IServiceManager.getService(); 685 } 686 } 687 688 @VisibleForTesting getHostapdMockable()689 protected IHostapd getHostapdMockable() throws RemoteException { 690 synchronized (mLock) { 691 return IHostapd.getService(); 692 } 693 } 694 695 @VisibleForTesting getHostapdMockableV1_1()696 protected android.hardware.wifi.hostapd.V1_1.IHostapd getHostapdMockableV1_1() 697 throws RemoteException { 698 synchronized (mLock) { 699 try { 700 return android.hardware.wifi.hostapd.V1_1.IHostapd.castFrom(mIHostapd); 701 } catch (NoSuchElementException e) { 702 Log.e(TAG, "Failed to get IHostapd", e); 703 return null; 704 } 705 } 706 } 707 708 @VisibleForTesting getHostapdMockableV1_2()709 protected android.hardware.wifi.hostapd.V1_2.IHostapd getHostapdMockableV1_2() 710 throws RemoteException { 711 synchronized (mLock) { 712 try { 713 return android.hardware.wifi.hostapd.V1_2.IHostapd.castFrom(mIHostapd); 714 } catch (NoSuchElementException e) { 715 Log.e(TAG, "Failed to get IHostapd", e); 716 return null; 717 } 718 } 719 } 720 721 @VisibleForTesting getHostapdMockableV1_3()722 protected android.hardware.wifi.hostapd.V1_3.IHostapd getHostapdMockableV1_3() 723 throws RemoteException { 724 synchronized (mLock) { 725 try { 726 return android.hardware.wifi.hostapd.V1_3.IHostapd.castFrom(mIHostapd); 727 } catch (NoSuchElementException e) { 728 Log.e(TAG, "Failed to get IHostapd", e); 729 return null; 730 } 731 } 732 } 733 updateIfaceParams_1_2FromResource( android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParams12)734 private void updateIfaceParams_1_2FromResource( 735 android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParams12) { 736 ifaceParams12.hwModeParams.enable80211AX = 737 mContext.getResources().getBoolean( 738 R.bool.config_wifiSoftapIeee80211axSupported); 739 ifaceParams12.hwModeParams.enable6GhzBand = 740 ApConfigUtil.isBandSupported(SoftApConfiguration.BAND_6GHZ, mContext); 741 ifaceParams12.hwModeParams.enableHeSingleUserBeamformer = 742 mContext.getResources().getBoolean( 743 R.bool.config_wifiSoftapHeSuBeamformerSupported); 744 ifaceParams12.hwModeParams.enableHeSingleUserBeamformee = 745 mContext.getResources().getBoolean( 746 R.bool.config_wifiSoftapHeSuBeamformeeSupported); 747 ifaceParams12.hwModeParams.enableHeMultiUserBeamformer = 748 mContext.getResources().getBoolean( 749 R.bool.config_wifiSoftapHeMuBeamformerSupported); 750 ifaceParams12.hwModeParams.enableHeTargetWakeTime = 751 mContext.getResources().getBoolean(R.bool.config_wifiSoftapHeTwtSupported); 752 } 753 754 private android.hardware.wifi.hostapd.V1_0.IHostapd.IfaceParams prepareIfaceParamsV1_0(String ifaceName, SoftApConfiguration config)755 prepareIfaceParamsV1_0(String ifaceName, SoftApConfiguration config) { 756 IHostapd.IfaceParams ifaceParamsV1_0 = new IHostapd.IfaceParams(); 757 ifaceParamsV1_0.ifaceName = ifaceName; 758 ifaceParamsV1_0.hwModeParams.enable80211N = true; 759 ifaceParamsV1_0.hwModeParams.enable80211AC = mContext.getResources().getBoolean( 760 R.bool.config_wifi_softap_ieee80211ac_supported); 761 boolean enableAcs = ApConfigUtil.isAcsSupported(mContext) && config.getChannel() == 0; 762 if (enableAcs) { 763 ifaceParamsV1_0.channelParams.enableAcs = true; 764 ifaceParamsV1_0.channelParams.acsShouldExcludeDfs = !mContext.getResources() 765 .getBoolean(R.bool.config_wifiSoftapAcsIncludeDfs); 766 } 767 ifaceParamsV1_0.channelParams.channel = config.getChannel(); 768 ifaceParamsV1_0.channelParams.band = getHalBand(config.getBand()); 769 return ifaceParamsV1_0; 770 } 771 772 private android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams prepareIfaceParamsV1_1( android.hardware.wifi.hostapd.V1_0.IHostapd.IfaceParams ifaceParamsV10, SoftApConfiguration config)773 prepareIfaceParamsV1_1( 774 android.hardware.wifi.hostapd.V1_0.IHostapd.IfaceParams ifaceParamsV10, 775 SoftApConfiguration config) { 776 android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParamsV1_1 = 777 new android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams(); 778 ifaceParamsV1_1.V1_0 = ifaceParamsV10; 779 ifaceParamsV10.channelParams.band = getHalBand(config.getBand()); 780 781 if (ifaceParamsV10.channelParams.enableAcs) { 782 if ((config.getBand() & SoftApConfiguration.BAND_2GHZ) != 0) { 783 ifaceParamsV1_1.channelParams.acsChannelRanges.addAll( 784 toAcsChannelRanges(mContext.getResources().getString( 785 R.string.config_wifiSoftap2gChannelList))); 786 } 787 if ((config.getBand() & SoftApConfiguration.BAND_5GHZ) != 0) { 788 ifaceParamsV1_1.channelParams.acsChannelRanges.addAll( 789 toAcsChannelRanges(mContext.getResources().getString( 790 R.string.config_wifiSoftap5gChannelList))); 791 } 792 } 793 return ifaceParamsV1_1; 794 } 795 796 private android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams prepareIfaceParamsV1_2( android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParamsV11, SoftApConfiguration config)797 prepareIfaceParamsV1_2( 798 android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParamsV11, 799 SoftApConfiguration config) { 800 android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParamsV1_2 = 801 new android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams(); 802 ifaceParamsV1_2.V1_1 = ifaceParamsV11; 803 updateIfaceParams_1_2FromResource(ifaceParamsV1_2); 804 //Update 80211ax support with the configuration. 805 ifaceParamsV1_2.hwModeParams.enable80211AX &= config.isIeee80211axEnabledInternal(); 806 807 ifaceParamsV1_2.channelParams.bandMask = getHalBandMask(config.getBand()); 808 809 // Prepare freq ranges/lists if needed 810 if (ifaceParamsV11.V1_0.channelParams.enableAcs && ApConfigUtil.isSendFreqRangesNeeded( 811 config.getBand(), mContext)) { 812 prepareAcsChannelFreqRangesMhz(ifaceParamsV1_2.channelParams, config.getBand()); 813 } 814 return ifaceParamsV1_2; 815 } 816 817 private android.hardware.wifi.hostapd.V1_3.IHostapd.IfaceParams prepareIfaceParamsV1_3( android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParamsV12, SoftApConfiguration config)818 prepareIfaceParamsV1_3( 819 android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParamsV12, 820 SoftApConfiguration config) { 821 android.hardware.wifi.hostapd.V1_3.IHostapd.IfaceParams ifaceParamsV1_3 = 822 new android.hardware.wifi.hostapd.V1_3.IHostapd.IfaceParams(); 823 ifaceParamsV1_3.V1_2 = ifaceParamsV12; 824 ArrayList<android.hardware.wifi.hostapd.V1_3.IHostapd.ChannelParams> 825 channelParams1_3List = new ArrayList<>(); 826 if (!SdkLevel.isAtLeastS()) { 827 return ifaceParamsV1_3; 828 } 829 for (int i = 0; i < config.getChannels().size(); i++) { 830 android.hardware.wifi.hostapd.V1_3.IHostapd.ChannelParams channelParam13 = 831 new android.hardware.wifi.hostapd.V1_3.IHostapd.ChannelParams(); 832 // Prepare channel 833 channelParam13.channel = config.getChannels().valueAt(i); 834 // Prepare enableAcs 835 channelParam13.enableAcs = ApConfigUtil.isAcsSupported(mContext) 836 && channelParam13.channel == 0; 837 // Prepare the bandMask 838 channelParam13.V1_2.bandMask = getHalBandMask(config.getChannels().keyAt(i)); 839 channelParam13.bandMask = channelParam13.V1_2.bandMask; 840 // Prepare AcsChannelFreqRangesMhz 841 if (channelParam13.enableAcs && ApConfigUtil.isSendFreqRangesNeeded( 842 config.getChannels().keyAt(i), mContext)) { 843 prepareAcsChannelFreqRangesMhz( 844 channelParam13.V1_2, config.getChannels().keyAt(i)); 845 } 846 channelParams1_3List.add(channelParam13); 847 } 848 ifaceParamsV1_3.channelParamsList = channelParams1_3List; 849 return ifaceParamsV1_3; 850 } 851 852 private android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams prepareNetworkParamsV1_2(SoftApConfiguration config)853 prepareNetworkParamsV1_2(SoftApConfiguration config) { 854 android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams nwParamsV1_2 = 855 new android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams(); 856 nwParamsV1_2.V1_0.ssid.addAll(NativeUtil.stringToByteArrayList(config.getSsid())); 857 nwParamsV1_2.V1_0.isHidden = config.isHiddenSsid(); 858 int encryptionType = getEncryptionType(config); 859 nwParamsV1_2.encryptionType = encryptionType; 860 nwParamsV1_2.passphrase = (config.getPassphrase() != null) 861 ? config.getPassphrase() : ""; 862 if (encryptionType 863 == android.hardware.wifi.hostapd.V1_2.IHostapd.EncryptionType.WPA3_SAE 864 || encryptionType == android.hardware.wifi.hostapd.V1_2.IHostapd 865 .EncryptionType.WPA3_SAE_TRANSITION) { 866 if (!isV1_2()) { 867 // It should not happen since we should reject configuration in SoftApManager 868 Log.e(TAG, "Unsupported Configuration found: " + config); 869 return null; 870 } 871 } else { 872 // Fill old parameter for old hidl. 873 nwParamsV1_2.V1_0.encryptionType = encryptionType; 874 nwParamsV1_2.V1_0.pskPassphrase = (config.getPassphrase() != null) 875 ? config.getPassphrase() : ""; 876 } 877 return nwParamsV1_2; 878 } 879 getEncryptionType(SoftApConfiguration localConfig)880 private static int getEncryptionType(SoftApConfiguration localConfig) { 881 int encryptionType; 882 switch (localConfig.getSecurityType()) { 883 case SoftApConfiguration.SECURITY_TYPE_OPEN: 884 encryptionType = IHostapd.EncryptionType.NONE; 885 break; 886 case SoftApConfiguration.SECURITY_TYPE_WPA2_PSK: 887 encryptionType = IHostapd.EncryptionType.WPA2; 888 break; 889 case SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION: 890 encryptionType = android.hardware.wifi.hostapd.V1_2 891 .IHostapd.EncryptionType.WPA3_SAE_TRANSITION; 892 break; 893 case SoftApConfiguration.SECURITY_TYPE_WPA3_SAE: 894 encryptionType = android.hardware.wifi.hostapd.V1_2 895 .IHostapd.EncryptionType.WPA3_SAE; 896 break; 897 default: 898 // We really shouldn't default to None, but this was how NetworkManagementService 899 // used to do this. 900 encryptionType = IHostapd.EncryptionType.NONE; 901 break; 902 } 903 return encryptionType; 904 } 905 getHalBandMask(int apBand)906 private static int getHalBandMask(int apBand) { 907 int bandMask = 0; 908 909 if (!ApConfigUtil.isBandValid(apBand)) { 910 throw new IllegalArgumentException(); 911 } 912 913 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_2GHZ)) { 914 bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_2_GHZ; 915 } 916 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_5GHZ)) { 917 bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_5_GHZ; 918 } 919 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_6GHZ)) { 920 bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_6_GHZ; 921 } 922 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_60GHZ)) { 923 bandMask |= android.hardware.wifi.hostapd.V1_3.IHostapd.BandMask.BAND_60_GHZ; 924 } 925 926 return bandMask; 927 } 928 getHalBand(int apBand)929 private static int getHalBand(int apBand) { 930 if (!ApConfigUtil.isBandValid(apBand)) { 931 throw new IllegalArgumentException(); 932 } 933 934 switch (apBand) { 935 case SoftApConfiguration.BAND_2GHZ: 936 return IHostapd.Band.BAND_2_4_GHZ; 937 case SoftApConfiguration.BAND_5GHZ: 938 return IHostapd.Band.BAND_5_GHZ; 939 default: 940 return IHostapd.Band.BAND_ANY; 941 } 942 } 943 944 /** 945 * Convert channel list string like '1-6,11' to list of AcsChannelRanges 946 */ 947 private List<android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange> toAcsChannelRanges(String channelListStr)948 toAcsChannelRanges(String channelListStr) { 949 ArrayList<android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange> acsChannelRanges = 950 new ArrayList<>(); 951 952 for (String channelRange : channelListStr.split(",")) { 953 android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange acsChannelRange = 954 new android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange(); 955 try { 956 if (channelRange.contains("-")) { 957 String[] channels = channelRange.split("-"); 958 if (channels.length != 2) { 959 Log.e(TAG, "Unrecognized channel range, length is " + channels.length); 960 continue; 961 } 962 int start = Integer.parseInt(channels[0].trim()); 963 int end = Integer.parseInt(channels[1].trim()); 964 if (start > end) { 965 Log.e(TAG, "Invalid channel range, from " + start + " to " + end); 966 continue; 967 } 968 acsChannelRange.start = start; 969 acsChannelRange.end = end; 970 } else if (!TextUtils.isEmpty(channelRange)) { 971 acsChannelRange.start = Integer.parseInt(channelRange.trim()); 972 acsChannelRange.end = acsChannelRange.start; 973 } 974 } catch (NumberFormatException e) { 975 // Ignore malformed value 976 Log.e(TAG, "Malformed channel value detected: " + e); 977 continue; 978 } 979 acsChannelRanges.add(acsChannelRange); 980 } 981 return acsChannelRanges; 982 } 983 984 985 /** 986 * Prepare the acsChannelFreqRangesMhz in V1_2.IHostapd.ChannelParams. 987 */ prepareAcsChannelFreqRangesMhz( android.hardware.wifi.hostapd.V1_2.IHostapd.ChannelParams channelParams12, @BandType int band)988 private void prepareAcsChannelFreqRangesMhz( 989 android.hardware.wifi.hostapd.V1_2.IHostapd.ChannelParams channelParams12, 990 @BandType int band) { 991 if ((band & SoftApConfiguration.BAND_2GHZ) != 0) { 992 channelParams12.acsChannelFreqRangesMhz.addAll( 993 toAcsFreqRanges(SoftApConfiguration.BAND_2GHZ)); 994 } 995 if ((band & SoftApConfiguration.BAND_5GHZ) != 0) { 996 channelParams12.acsChannelFreqRangesMhz.addAll( 997 toAcsFreqRanges(SoftApConfiguration.BAND_5GHZ)); 998 } 999 if ((band & SoftApConfiguration.BAND_6GHZ) != 0) { 1000 channelParams12.acsChannelFreqRangesMhz.addAll( 1001 toAcsFreqRanges(SoftApConfiguration.BAND_6GHZ)); 1002 } 1003 } 1004 1005 /** 1006 * Convert channel list string like '1-6,11' to list of AcsFreqRange 1007 */ 1008 private List<android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange> toAcsFreqRanges(@andType int band)1009 toAcsFreqRanges(@BandType int band) { 1010 List<android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange> 1011 acsFrequencyRanges = new ArrayList<>(); 1012 1013 if (!ApConfigUtil.isBandValid(band) || ApConfigUtil.isMultiband(band)) { 1014 Log.e(TAG, "Invalid band : " + band); 1015 return acsFrequencyRanges; 1016 } 1017 1018 String channelListStr; 1019 switch (band) { 1020 case SoftApConfiguration.BAND_2GHZ: 1021 channelListStr = mContext.getResources().getString( 1022 R.string.config_wifiSoftap2gChannelList); 1023 if (TextUtils.isEmpty(channelListStr)) { 1024 channelListStr = ScanResult.BAND_24_GHZ_FIRST_CH_NUM + "-" 1025 + ScanResult.BAND_24_GHZ_LAST_CH_NUM; 1026 } 1027 break; 1028 case SoftApConfiguration.BAND_5GHZ: 1029 channelListStr = mContext.getResources().getString( 1030 R.string.config_wifiSoftap5gChannelList); 1031 if (TextUtils.isEmpty(channelListStr)) { 1032 channelListStr = ScanResult.BAND_5_GHZ_FIRST_CH_NUM + "-" 1033 + ScanResult.BAND_5_GHZ_LAST_CH_NUM; 1034 } 1035 break; 1036 case SoftApConfiguration.BAND_6GHZ: 1037 channelListStr = mContext.getResources().getString( 1038 R.string.config_wifiSoftap6gChannelList); 1039 if (TextUtils.isEmpty(channelListStr)) { 1040 channelListStr = ScanResult.BAND_6_GHZ_FIRST_CH_NUM + "-" 1041 + ScanResult.BAND_6_GHZ_LAST_CH_NUM; 1042 } 1043 break; 1044 default: 1045 return acsFrequencyRanges; 1046 } 1047 1048 for (String channelRange : channelListStr.split(",")) { 1049 android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange acsFrequencyRange = 1050 new android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange(); 1051 try { 1052 if (channelRange.contains("-")) { 1053 String[] channels = channelRange.split("-"); 1054 if (channels.length != 2) { 1055 Log.e(TAG, "Unrecognized channel range, length is " + channels.length); 1056 continue; 1057 } 1058 int start = Integer.parseInt(channels[0].trim()); 1059 int end = Integer.parseInt(channels[1].trim()); 1060 if (start > end) { 1061 Log.e(TAG, "Invalid channel range, from " + start + " to " + end); 1062 continue; 1063 } 1064 acsFrequencyRange.start = ApConfigUtil.convertChannelToFrequency(start, band); 1065 acsFrequencyRange.end = ApConfigUtil.convertChannelToFrequency(end, band); 1066 } else if (!TextUtils.isEmpty(channelRange)) { 1067 int channel = Integer.parseInt(channelRange.trim()); 1068 acsFrequencyRange.start = ApConfigUtil.convertChannelToFrequency(channel, band); 1069 acsFrequencyRange.end = acsFrequencyRange.start; 1070 } 1071 } catch (NumberFormatException e) { 1072 // Ignore malformed value 1073 Log.e(TAG, "Malformed channel value detected: " + e); 1074 continue; 1075 } 1076 acsFrequencyRanges.add(acsFrequencyRange); 1077 } 1078 return acsFrequencyRanges; 1079 } 1080 1081 /** 1082 * Returns false if Hostapd is null, and logs failure to call methodStr 1083 */ checkHostapdAndLogFailure(String methodStr)1084 private boolean checkHostapdAndLogFailure(String methodStr) { 1085 synchronized (mLock) { 1086 if (mIHostapd == null) { 1087 Log.e(TAG, "Can't call " + methodStr + ", IHostapd is null"); 1088 return false; 1089 } 1090 return true; 1091 } 1092 } 1093 1094 /** 1095 * Returns true if provided status code is SUCCESS, logs debug message and returns false 1096 * otherwise 1097 */ checkStatusAndLogFailure(HostapdStatus status, String methodStr)1098 private boolean checkStatusAndLogFailure(HostapdStatus status, 1099 String methodStr) { 1100 synchronized (mLock) { 1101 if (status.code != HostapdStatusCode.SUCCESS) { 1102 Log.e(TAG, "IHostapd." + methodStr + " failed: " + status.code 1103 + ", " + status.debugMessage); 1104 return false; 1105 } else { 1106 if (mVerboseLoggingEnabled) { 1107 Log.d(TAG, "IHostapd." + methodStr + " succeeded"); 1108 } 1109 return true; 1110 } 1111 } 1112 } 1113 1114 /** 1115 * Returns true if provided status code is SUCCESS, logs debug message and returns false 1116 * otherwise 1117 */ checkStatusAndLogFailure12( android.hardware.wifi.hostapd.V1_2.HostapdStatus status, String methodStr)1118 private boolean checkStatusAndLogFailure12( 1119 android.hardware.wifi.hostapd.V1_2.HostapdStatus status, String methodStr) { 1120 synchronized (mLock) { 1121 if (status.code != HostapdStatusCode.SUCCESS) { 1122 Log.e(TAG, "IHostapd." + methodStr + " failed: " + status.code 1123 + ", " + status.debugMessage); 1124 return false; 1125 } else { 1126 if (mVerboseLoggingEnabled) { 1127 Log.d(TAG, "IHostapd." + methodStr + " succeeded"); 1128 } 1129 return true; 1130 } 1131 } 1132 } 1133 handleRemoteException(RemoteException e, String methodStr)1134 private void handleRemoteException(RemoteException e, String methodStr) { 1135 synchronized (mLock) { 1136 hostapdServiceDiedHandler(mDeathRecipientCookie); 1137 Log.e(TAG, "IHostapd." + methodStr + " failed with exception", e); 1138 } 1139 } 1140 1141 private class HostapdCallback extends 1142 android.hardware.wifi.hostapd.V1_1.IHostapdCallback.Stub { 1143 @Override onFailure(String ifaceName)1144 public void onFailure(String ifaceName) { 1145 Log.w(TAG, "Failure on iface " + ifaceName); 1146 Runnable onFailureListener = mSoftApFailureListeners.get(ifaceName); 1147 if (onFailureListener != null) { 1148 onFailureListener.run(); 1149 } 1150 } 1151 } 1152 1153 /** 1154 * Map hal bandwidth to SoftApInfo. 1155 * 1156 * @param bandwidth The channel bandwidth of the AP which is defined in the HAL. 1157 * @return The channel bandwidth in the SoftApinfo. 1158 */ 1159 @VisibleForTesting mapHalBandwidthToSoftApInfo(int bandwidth)1160 public int mapHalBandwidthToSoftApInfo(int bandwidth) { 1161 switch (bandwidth) { 1162 case Bandwidth.WIFI_BANDWIDTH_20_NOHT: 1163 return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT; 1164 case Bandwidth.WIFI_BANDWIDTH_20: 1165 return SoftApInfo.CHANNEL_WIDTH_20MHZ; 1166 case Bandwidth.WIFI_BANDWIDTH_40: 1167 return SoftApInfo.CHANNEL_WIDTH_40MHZ; 1168 case Bandwidth.WIFI_BANDWIDTH_80: 1169 return SoftApInfo.CHANNEL_WIDTH_80MHZ; 1170 case Bandwidth.WIFI_BANDWIDTH_80P80: 1171 return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; 1172 case Bandwidth.WIFI_BANDWIDTH_160: 1173 return SoftApInfo.CHANNEL_WIDTH_160MHZ; 1174 case Bandwidth.WIFI_BANDWIDTH_2160: 1175 return SoftApInfo.CHANNEL_WIDTH_2160MHZ; 1176 case Bandwidth.WIFI_BANDWIDTH_4320: 1177 return SoftApInfo.CHANNEL_WIDTH_4320MHZ; 1178 case Bandwidth.WIFI_BANDWIDTH_6480: 1179 return SoftApInfo.CHANNEL_WIDTH_6480MHZ; 1180 case Bandwidth.WIFI_BANDWIDTH_8640: 1181 return SoftApInfo.CHANNEL_WIDTH_8640MHZ; 1182 default: 1183 return SoftApInfo.CHANNEL_WIDTH_INVALID; 1184 } 1185 } 1186 1187 /** 1188 * Map hal generation to wifi standard. 1189 * 1190 * @param generation The operation mode of the AP which is defined in HAL. 1191 * @return The wifi standard in the ScanResult. 1192 */ 1193 @VisibleForTesting mapHalGenerationToWifiStandard(int generation)1194 public int mapHalGenerationToWifiStandard(int generation) { 1195 switch (generation) { 1196 case Generation.WIFI_STANDARD_LEGACY: 1197 return ScanResult.WIFI_STANDARD_LEGACY; 1198 case Generation.WIFI_STANDARD_11N: 1199 return ScanResult.WIFI_STANDARD_11N; 1200 case Generation.WIFI_STANDARD_11AC: 1201 return ScanResult.WIFI_STANDARD_11AC; 1202 case Generation.WIFI_STANDARD_11AX: 1203 return ScanResult.WIFI_STANDARD_11AX; 1204 case Generation.WIFI_STANDARD_11AD: 1205 return ScanResult.WIFI_STANDARD_11AD; 1206 default: 1207 return ScanResult.WIFI_STANDARD_UNKNOWN; 1208 } 1209 } 1210 1211 private class HostapdCallback_1_3 extends 1212 android.hardware.wifi.hostapd.V1_3.IHostapdCallback.Stub { 1213 @Override onFailure(String ifaceName)1214 public void onFailure(String ifaceName) { 1215 Log.w(TAG, "Failure on iface " + ifaceName); 1216 Runnable onFailureListener = mSoftApFailureListeners.get(ifaceName); 1217 if (onFailureListener != null) { 1218 onFailureListener.run(); 1219 } 1220 } 1221 1222 @Override onApInstanceInfoChanged(String ifaceName, String apIfaceInstance, int frequency, int bandwidth, int generation, byte[] apIfaceInstanceMacAddress)1223 public void onApInstanceInfoChanged(String ifaceName, String apIfaceInstance, 1224 int frequency, int bandwidth, int generation, byte[] apIfaceInstanceMacAddress) { 1225 Log.d(TAG, "onApInstanceInfoChanged on " + ifaceName + " / " + apIfaceInstance); 1226 try { 1227 if (mSoftApEventListener != null) { 1228 mSoftApEventListener.onInfoChanged(apIfaceInstance, frequency, 1229 mapHalBandwidthToSoftApInfo(bandwidth), 1230 mapHalGenerationToWifiStandard(generation), 1231 MacAddress.fromBytes(apIfaceInstanceMacAddress)); 1232 } 1233 } catch (IllegalArgumentException iae) { 1234 Log.e(TAG, " Invalid apIfaceInstanceMacAddress, " + iae); 1235 } 1236 } 1237 1238 @Override onConnectedClientsChanged(String ifaceName, String apIfaceInstance, byte[] clientAddress, boolean isConnected)1239 public void onConnectedClientsChanged(String ifaceName, String apIfaceInstance, 1240 byte[] clientAddress, boolean isConnected) { 1241 try { 1242 Log.d(TAG, "onConnectedClientsChanged on " + ifaceName + " / " + apIfaceInstance 1243 + " and Mac is " + MacAddress.fromBytes(clientAddress).toString() 1244 + " isConnected: " + isConnected); 1245 if (mSoftApEventListener != null) { 1246 mSoftApEventListener.onConnectedClientsChanged(apIfaceInstance, 1247 MacAddress.fromBytes(clientAddress), isConnected); 1248 } 1249 } catch (IllegalArgumentException iae) { 1250 Log.e(TAG, " Invalid clientAddress, " + iae); 1251 } 1252 } 1253 } 1254 1255 /** 1256 * Set the debug log level for hostapd. 1257 * 1258 * @return true if request is sent successfully, false otherwise. 1259 */ setLogLevel()1260 public boolean setLogLevel() { 1261 synchronized (mLock) { 1262 final String methodStr = "setDebugParams"; 1263 if (!checkHostapdAndLogFailure(methodStr)) return false; 1264 if (isV1_2()) { 1265 try { 1266 android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 = 1267 getHostapdMockableV1_2(); 1268 if (iHostapdV1_2 == null) return false; 1269 android.hardware.wifi.hostapd.V1_2.HostapdStatus status = 1270 iHostapdV1_2.setDebugParams(mVerboseLoggingEnabled 1271 ? DebugLevel.DEBUG 1272 : DebugLevel.INFO); 1273 return checkStatusAndLogFailure12(status, methodStr); 1274 } catch (RemoteException e) { 1275 handleRemoteException(e, methodStr); 1276 } 1277 } else { 1278 Log.d(TAG, "HIDL doesn't support setDebugParams"); 1279 } 1280 return false; 1281 } 1282 } 1283 } 1284