Home | History | Annotate | Download | only in aware
      1 /*
      2  * Copyright (C) 2016 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 
     17 package com.android.server.wifi.aware;
     18 
     19 import android.hardware.wifi.V1_0.IWifiNanIface;
     20 import android.hardware.wifi.V1_0.NanBandIndex;
     21 import android.hardware.wifi.V1_0.NanBandSpecificConfig;
     22 import android.hardware.wifi.V1_0.NanCipherSuiteType;
     23 import android.hardware.wifi.V1_0.NanConfigRequest;
     24 import android.hardware.wifi.V1_0.NanDataPathSecurityType;
     25 import android.hardware.wifi.V1_0.NanEnableRequest;
     26 import android.hardware.wifi.V1_0.NanInitiateDataPathRequest;
     27 import android.hardware.wifi.V1_0.NanMatchAlg;
     28 import android.hardware.wifi.V1_0.NanPublishRequest;
     29 import android.hardware.wifi.V1_0.NanRangingIndication;
     30 import android.hardware.wifi.V1_0.NanRespondToDataPathIndicationRequest;
     31 import android.hardware.wifi.V1_0.NanSubscribeRequest;
     32 import android.hardware.wifi.V1_0.NanTransmitFollowupRequest;
     33 import android.hardware.wifi.V1_0.NanTxType;
     34 import android.hardware.wifi.V1_0.WifiStatus;
     35 import android.hardware.wifi.V1_0.WifiStatusCode;
     36 import android.hardware.wifi.V1_2.NanConfigRequestSupplemental;
     37 import android.net.wifi.aware.ConfigRequest;
     38 import android.net.wifi.aware.PublishConfig;
     39 import android.net.wifi.aware.SubscribeConfig;
     40 import android.os.RemoteException;
     41 import android.os.ShellCommand;
     42 import android.util.Log;
     43 import android.util.SparseIntArray;
     44 
     45 import libcore.util.HexEncoding;
     46 
     47 import java.io.FileDescriptor;
     48 import java.io.PrintWriter;
     49 import java.nio.charset.StandardCharsets;
     50 import java.util.ArrayList;
     51 import java.util.HashMap;
     52 import java.util.Map;
     53 
     54 /**
     55  * Translates Wi-Fi Aware requests from the framework to the HAL (HIDL).
     56  *
     57  * Delegates the management of the NAN interface to WifiAwareNativeManager.
     58  */
     59 public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand {
     60     private static final String TAG = "WifiAwareNativeApi";
     61     private static final boolean VDBG = false; // STOPSHIP if true
     62     /* package */ boolean mDbg = false;
     63 
     64     private static final String SERVICE_NAME_FOR_OOB_DATA_PATH = "Wi-Fi Aware Data Path";
     65 
     66     private final WifiAwareNativeManager mHal;
     67     private SparseIntArray mTransactionIds; // VDBG only!
     68 
     69     public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) {
     70         mHal = wifiAwareNativeManager;
     71         onReset();
     72         if (VDBG) {
     73             mTransactionIds = new SparseIntArray();
     74         }
     75     }
     76 
     77     private void recordTransactionId(int transactionId) {
     78         if (!VDBG) return;
     79 
     80         if (transactionId == 0) {
     81             return; // tid == 0 is used as a dummy transaction ID in several commands - acceptable
     82         }
     83 
     84         int count = mTransactionIds.get(transactionId);
     85         if (count != 0) {
     86             Log.wtf(TAG, "Repeated transaction ID == " + transactionId);
     87         }
     88         mTransactionIds.append(transactionId, count + 1);
     89     }
     90 
     91     /**
     92      * (HIDL) Cast the input to a 1.2 NAN interface (possibly resulting in a null).
     93      *
     94      * Separate function so can be mocked in unit tests.
     95      */
     96     public android.hardware.wifi.V1_2.IWifiNanIface mockableCastTo_1_2(IWifiNanIface iface) {
     97         return android.hardware.wifi.V1_2.IWifiNanIface.castFrom(iface);
     98     }
     99 
    100     /*
    101      * Parameters settable through the shell command.
    102      * see wifi/1.0/types.hal NanBandSpecificConfig.discoveryWindowIntervalVal and
    103      * wifi/1.2/types.hal NanConfigRequestSupplemental_1_2 for description
    104      */
    105     /* package */ static final String POWER_PARAM_DEFAULT_KEY = "default";
    106     /* package */ static final String POWER_PARAM_INACTIVE_KEY = "inactive";
    107     /* package */ static final String POWER_PARAM_IDLE_KEY = "idle";
    108 
    109     /* package */ static final String PARAM_DW_24GHZ = "dw_24ghz";
    110     private static final int PARAM_DW_24GHZ_DEFAULT = -1; // Firmware default
    111     private static final int PARAM_DW_24GHZ_INACTIVE = 4; // 4 -> DW=8, latency=4s
    112     private static final int PARAM_DW_24GHZ_IDLE = 4; // == inactive
    113 
    114     /* package */ static final String PARAM_DW_5GHZ = "dw_5ghz";
    115     private static final int PARAM_DW_5GHZ_DEFAULT = -1; // Firmware default
    116     private static final int PARAM_DW_5GHZ_INACTIVE = 0; // 0 = disabled
    117     private static final int PARAM_DW_5GHZ_IDLE = 0; // == inactive
    118 
    119     /* package */ static final String PARAM_DISCOVERY_BEACON_INTERVAL_MS =
    120             "disc_beacon_interval_ms";
    121     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT = 0; // Firmware defaults
    122     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE = 0; // Firmware defaults
    123     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE = 0; // Firmware defaults
    124 
    125     /* package */ static final String PARAM_NUM_SS_IN_DISCOVERY = "num_ss_in_discovery";
    126     private static final int PARAM_NUM_SS_IN_DISCOVERY_DEFAULT = 0; // Firmware defaults
    127     private static final int PARAM_NUM_SS_IN_DISCOVERY_INACTIVE = 0; // Firmware defaults
    128     private static final int PARAM_NUM_SS_IN_DISCOVERY_IDLE = 0; // Firmware defaults
    129 
    130     /* package */ static final String PARAM_ENABLE_DW_EARLY_TERM = "enable_dw_early_term";
    131     private static final int PARAM_ENABLE_DW_EARLY_TERM_DEFAULT = 0; // boolean: 0 = false
    132     private static final int PARAM_ENABLE_DW_EARLY_TERM_INACTIVE = 0; // boolean: 0 = false
    133     private static final int PARAM_ENABLE_DW_EARLY_TERM_IDLE = 0; // boolean: 0 = false
    134 
    135     /* package */ static final String PARAM_MAC_RANDOM_INTERVAL_SEC = "mac_random_interval_sec";
    136     private static final int PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT = 1800; // 30 minutes
    137 
    138     private Map<String, Map<String, Integer>> mSettablePowerParameters = new HashMap<>();
    139     private Map<String, Integer> mSettableParameters = new HashMap<>();
    140 
    141     /**
    142      * Interpreter of adb shell command 'adb shell wifiaware native_api ...'.
    143      *
    144      * @return -1 if parameter not recognized or invalid value, 0 otherwise.
    145      */
    146     @Override
    147     public int onCommand(ShellCommand parentShell) {
    148         final PrintWriter pw = parentShell.getErrPrintWriter();
    149 
    150         String subCmd = parentShell.getNextArgRequired();
    151         if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'");
    152         switch (subCmd) {
    153             case "set": {
    154                 String name = parentShell.getNextArgRequired();
    155                 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'");
    156                 if (!mSettableParameters.containsKey(name)) {
    157                     pw.println("Unknown parameter name -- '" + name + "'");
    158                     return -1;
    159                 }
    160 
    161                 String valueStr = parentShell.getNextArgRequired();
    162                 if (VDBG) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'");
    163                 int value;
    164                 try {
    165                     value = Integer.valueOf(valueStr);
    166                 } catch (NumberFormatException e) {
    167                     pw.println("Can't convert value to integer -- '" + valueStr + "'");
    168                     return -1;
    169                 }
    170                 mSettableParameters.put(name, value);
    171                 return 0;
    172             }
    173             case "set-power": {
    174                 String mode = parentShell.getNextArgRequired();
    175                 String name = parentShell.getNextArgRequired();
    176                 String valueStr = parentShell.getNextArgRequired();
    177 
    178                 if (VDBG) {
    179                     Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'" + ", value='"
    180                             + valueStr + "'");
    181                 }
    182 
    183                 if (!mSettablePowerParameters.containsKey(mode)) {
    184                     pw.println("Unknown mode name -- '" + mode + "'");
    185                     return -1;
    186                 }
    187                 if (!mSettablePowerParameters.get(mode).containsKey(name)) {
    188                     pw.println("Unknown parameter name '" + name + "' in mode '" + mode + "'");
    189                     return -1;
    190                 }
    191 
    192                 int value;
    193                 try {
    194                     value = Integer.valueOf(valueStr);
    195                 } catch (NumberFormatException e) {
    196                     pw.println("Can't convert value to integer -- '" + valueStr + "'");
    197                     return -1;
    198                 }
    199                 mSettablePowerParameters.get(mode).put(name, value);
    200                 return 0;
    201             }
    202             case "get": {
    203                 String name = parentShell.getNextArgRequired();
    204                 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'");
    205                 if (!mSettableParameters.containsKey(name)) {
    206                     pw.println("Unknown parameter name -- '" + name + "'");
    207                     return -1;
    208                 }
    209 
    210                 parentShell.getOutPrintWriter().println((int) mSettableParameters.get(name));
    211                 return 0;
    212             }
    213             case "get-power": {
    214                 String mode = parentShell.getNextArgRequired();
    215                 String name = parentShell.getNextArgRequired();
    216                 if (VDBG) Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'");
    217                 if (!mSettablePowerParameters.containsKey(mode)) {
    218                     pw.println("Unknown mode -- '" + mode + "'");
    219                     return -1;
    220                 }
    221                 if (!mSettablePowerParameters.get(mode).containsKey(name)) {
    222                     pw.println("Unknown parameter name -- '" + name + "' in mode '" + mode + "'");
    223                     return -1;
    224                 }
    225 
    226                 parentShell.getOutPrintWriter().println(
    227                         (int) mSettablePowerParameters.get(mode).get(name));
    228                 return 0;
    229             }
    230             default:
    231                 pw.println("Unknown 'wifiaware native_api <cmd>'");
    232         }
    233 
    234         return -1;
    235     }
    236 
    237     @Override
    238     public void onReset() {
    239         Map<String, Integer> defaultMap = new HashMap<>();
    240         defaultMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_DEFAULT);
    241         defaultMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_DEFAULT);
    242         defaultMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
    243                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT);
    244         defaultMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_DEFAULT);
    245         defaultMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_DEFAULT);
    246 
    247         Map<String, Integer> inactiveMap = new HashMap<>();
    248         inactiveMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_INACTIVE);
    249         inactiveMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_INACTIVE);
    250         inactiveMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
    251                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE);
    252         inactiveMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_INACTIVE);
    253         inactiveMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_INACTIVE);
    254 
    255         Map<String, Integer> idleMap = new HashMap<>();
    256         idleMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_IDLE);
    257         idleMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_IDLE);
    258         idleMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
    259                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE);
    260         idleMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_IDLE);
    261         idleMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_IDLE);
    262 
    263         mSettablePowerParameters.put(POWER_PARAM_DEFAULT_KEY, defaultMap);
    264         mSettablePowerParameters.put(POWER_PARAM_INACTIVE_KEY, inactiveMap);
    265         mSettablePowerParameters.put(POWER_PARAM_IDLE_KEY, idleMap);
    266 
    267         mSettableParameters.put(PARAM_MAC_RANDOM_INTERVAL_SEC,
    268                 PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT);
    269     }
    270 
    271     @Override
    272     public void onHelp(String command, ShellCommand parentShell) {
    273         final PrintWriter pw = parentShell.getOutPrintWriter();
    274 
    275         pw.println("  " + command);
    276         pw.println("    set <name> <value>: sets named parameter to value. Names: "
    277                 + mSettableParameters.keySet());
    278         pw.println("    set-power <mode> <name> <value>: sets named power parameter to value."
    279                 + " Modes: " + mSettablePowerParameters.keySet()
    280                 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet());
    281         pw.println("    get <name>: gets named parameter value. Names: "
    282                 + mSettableParameters.keySet());
    283         pw.println("    get-power <mode> <name>: gets named parameter value."
    284                 + " Modes: " + mSettablePowerParameters.keySet()
    285                 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet());
    286     }
    287 
    288     /**
    289      * Query the firmware's capabilities.
    290      *
    291      * @param transactionId Transaction ID for the transaction - used in the async callback to
    292      *                      match with the original request.
    293      */
    294     public boolean getCapabilities(short transactionId) {
    295         if (mDbg) Log.v(TAG, "getCapabilities: transactionId=" + transactionId);
    296         recordTransactionId(transactionId);
    297 
    298         IWifiNanIface iface = mHal.getWifiNanIface();
    299         if (iface == null) {
    300             Log.e(TAG, "getCapabilities: null interface");
    301             return false;
    302         }
    303 
    304         try {
    305             WifiStatus status = iface.getCapabilitiesRequest(transactionId);
    306             if (status.code == WifiStatusCode.SUCCESS) {
    307                 return true;
    308             } else {
    309                 Log.e(TAG, "getCapabilities: error: " + statusString(status));
    310                 return false;
    311             }
    312         } catch (RemoteException e) {
    313             Log.e(TAG, "getCapabilities: exception: " + e);
    314             return false;
    315         }
    316     }
    317 
    318     /**
    319      * Enable and configure Aware.
    320      *
    321      * @param transactionId Transaction ID for the transaction - used in the
    322      *            async callback to match with the original request.
    323      * @param configRequest Requested Aware configuration.
    324      * @param notifyIdentityChange Indicates whether or not to get address change callbacks.
    325      * @param initialConfiguration Specifies whether initial configuration
    326      *            (true) or an update (false) to the configuration.
    327      * @param isInteractive PowerManager.isInteractive
    328      * @param isIdle PowerManager.isIdle
    329      */
    330     public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest,
    331             boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive,
    332             boolean isIdle) {
    333         if (mDbg) {
    334             Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest="
    335                     + configRequest + ", notifyIdentityChange=" + notifyIdentityChange
    336                     + ", initialConfiguration=" + initialConfiguration
    337                     + ", isInteractive=" + isInteractive + ", isIdle=" + isIdle);
    338         }
    339         recordTransactionId(transactionId);
    340 
    341         IWifiNanIface iface = mHal.getWifiNanIface();
    342         if (iface == null) {
    343             Log.e(TAG, "enableAndConfigure: null interface");
    344             return false;
    345         }
    346         android.hardware.wifi.V1_2.IWifiNanIface iface12 = mockableCastTo_1_2(iface);
    347         NanConfigRequestSupplemental configSupplemental12 = new NanConfigRequestSupplemental();
    348         if (iface12 != null) {
    349             if (VDBG) Log.v(TAG, "HAL 1.2 detected");
    350             configSupplemental12.discoveryBeaconIntervalMs = 0;
    351             configSupplemental12.numberOfSpatialStreamsInDiscovery = 0;
    352             configSupplemental12.enableDiscoveryWindowEarlyTermination = false;
    353             configSupplemental12.enableRanging = true;
    354         }
    355 
    356         try {
    357             WifiStatus status;
    358             if (initialConfiguration) {
    359                 // translate framework to HIDL configuration
    360                 NanEnableRequest req = new NanEnableRequest();
    361 
    362                 req.operateInBand[NanBandIndex.NAN_BAND_24GHZ] = true;
    363                 req.operateInBand[NanBandIndex.NAN_BAND_5GHZ] = configRequest.mSupport5gBand;
    364                 req.hopCountMax = 2;
    365                 req.configParams.masterPref = (byte) configRequest.mMasterPreference;
    366                 req.configParams.disableDiscoveryAddressChangeIndication = !notifyIdentityChange;
    367                 req.configParams.disableStartedClusterIndication = !notifyIdentityChange;
    368                 req.configParams.disableJoinedClusterIndication = !notifyIdentityChange;
    369                 req.configParams.includePublishServiceIdsInBeacon = true;
    370                 req.configParams.numberOfPublishServiceIdsInBeacon = 0;
    371                 req.configParams.includeSubscribeServiceIdsInBeacon = true;
    372                 req.configParams.numberOfSubscribeServiceIdsInBeacon = 0;
    373                 req.configParams.rssiWindowSize = 8;
    374                 req.configParams.macAddressRandomizationIntervalSec = mSettableParameters.get(
    375                         PARAM_MAC_RANDOM_INTERVAL_SEC);
    376 
    377                 NanBandSpecificConfig config24 = new NanBandSpecificConfig();
    378                 config24.rssiClose = 60;
    379                 config24.rssiMiddle = 70;
    380                 config24.rssiCloseProximity = 60;
    381                 config24.dwellTimeMs = (byte) 200;
    382                 config24.scanPeriodSec = 20;
    383                 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]
    384                         == ConfigRequest.DW_INTERVAL_NOT_INIT) {
    385                     config24.validDiscoveryWindowIntervalVal = false;
    386                 } else {
    387                     config24.validDiscoveryWindowIntervalVal = true;
    388                     config24.discoveryWindowIntervalVal =
    389                             (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest
    390                                     .NAN_BAND_24GHZ];
    391                 }
    392                 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24;
    393 
    394                 NanBandSpecificConfig config5 = new NanBandSpecificConfig();
    395                 config5.rssiClose = 60;
    396                 config5.rssiMiddle = 75;
    397                 config5.rssiCloseProximity = 60;
    398                 config5.dwellTimeMs = (byte) 200;
    399                 config5.scanPeriodSec = 20;
    400                 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]
    401                         == ConfigRequest.DW_INTERVAL_NOT_INIT) {
    402                     config5.validDiscoveryWindowIntervalVal = false;
    403                 } else {
    404                     config5.validDiscoveryWindowIntervalVal = true;
    405                     config5.discoveryWindowIntervalVal =
    406                             (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest
    407                                     .NAN_BAND_5GHZ];
    408                 }
    409                 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5;
    410 
    411                 req.debugConfigs.validClusterIdVals = true;
    412                 req.debugConfigs.clusterIdTopRangeVal = (short) configRequest.mClusterHigh;
    413                 req.debugConfigs.clusterIdBottomRangeVal = (short) configRequest.mClusterLow;
    414                 req.debugConfigs.validIntfAddrVal = false;
    415                 req.debugConfigs.validOuiVal = false;
    416                 req.debugConfigs.ouiVal = 0;
    417                 req.debugConfigs.validRandomFactorForceVal = false;
    418                 req.debugConfigs.randomFactorForceVal = 0;
    419                 req.debugConfigs.validHopCountForceVal = false;
    420                 req.debugConfigs.hopCountForceVal = 0;
    421                 req.debugConfigs.validDiscoveryChannelVal = false;
    422                 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_24GHZ] = 0;
    423                 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_5GHZ] = 0;
    424                 req.debugConfigs.validUseBeaconsInBandVal = false;
    425                 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true;
    426                 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true;
    427                 req.debugConfigs.validUseSdfInBandVal = false;
    428                 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true;
    429                 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true;
    430 
    431                 updateConfigForPowerSettings(req.configParams, configSupplemental12, isInteractive,
    432                         isIdle);
    433 
    434                 if (iface12 != null) {
    435                     status = iface12.enableRequest_1_2(transactionId, req, configSupplemental12);
    436                 } else {
    437                     status = iface.enableRequest(transactionId, req);
    438                 }
    439             } else {
    440                 NanConfigRequest req = new NanConfigRequest();
    441                 req.masterPref = (byte) configRequest.mMasterPreference;
    442                 req.disableDiscoveryAddressChangeIndication = !notifyIdentityChange;
    443                 req.disableStartedClusterIndication = !notifyIdentityChange;
    444                 req.disableJoinedClusterIndication = !notifyIdentityChange;
    445                 req.includePublishServiceIdsInBeacon = true;
    446                 req.numberOfPublishServiceIdsInBeacon = 0;
    447                 req.includeSubscribeServiceIdsInBeacon = true;
    448                 req.numberOfSubscribeServiceIdsInBeacon = 0;
    449                 req.rssiWindowSize = 8;
    450                 req.macAddressRandomizationIntervalSec = mSettableParameters.get(
    451                         PARAM_MAC_RANDOM_INTERVAL_SEC);
    452 
    453                 NanBandSpecificConfig config24 = new NanBandSpecificConfig();
    454                 config24.rssiClose = 60;
    455                 config24.rssiMiddle = 70;
    456                 config24.rssiCloseProximity = 60;
    457                 config24.dwellTimeMs = (byte) 200;
    458                 config24.scanPeriodSec = 20;
    459                 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]
    460                         == ConfigRequest.DW_INTERVAL_NOT_INIT) {
    461                     config24.validDiscoveryWindowIntervalVal = false;
    462                 } else {
    463                     config24.validDiscoveryWindowIntervalVal = true;
    464                     config24.discoveryWindowIntervalVal =
    465                             (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest
    466                                     .NAN_BAND_24GHZ];
    467                 }
    468                 req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24;
    469 
    470                 NanBandSpecificConfig config5 = new NanBandSpecificConfig();
    471                 config5.rssiClose = 60;
    472                 config5.rssiMiddle = 75;
    473                 config5.rssiCloseProximity = 60;
    474                 config5.dwellTimeMs = (byte) 200;
    475                 config5.scanPeriodSec = 20;
    476                 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]
    477                         == ConfigRequest.DW_INTERVAL_NOT_INIT) {
    478                     config5.validDiscoveryWindowIntervalVal = false;
    479                 } else {
    480                     config5.validDiscoveryWindowIntervalVal = true;
    481                     config5.discoveryWindowIntervalVal =
    482                             (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest
    483                                     .NAN_BAND_5GHZ];
    484                 }
    485                 req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5;
    486 
    487                 updateConfigForPowerSettings(req, configSupplemental12, isInteractive, isIdle);
    488 
    489                 if (iface12 != null) {
    490                     status = iface12.configRequest_1_2(transactionId, req, configSupplemental12);
    491                 } else {
    492                     status = iface.configRequest(transactionId, req);
    493                 }
    494             }
    495             if (status.code == WifiStatusCode.SUCCESS) {
    496                 return true;
    497             } else {
    498                 Log.e(TAG, "enableAndConfigure: error: " + statusString(status));
    499                 return false;
    500             }
    501         } catch (RemoteException e) {
    502             Log.e(TAG, "enableAndConfigure: exception: " + e);
    503             return false;
    504         }
    505     }
    506 
    507     /**
    508      * Disable Aware.
    509      *
    510      * @param transactionId transactionId Transaction ID for the transaction -
    511      *            used in the async callback to match with the original request.
    512      */
    513     public boolean disable(short transactionId) {
    514         if (mDbg) Log.d(TAG, "disable");
    515         recordTransactionId(transactionId);
    516 
    517         IWifiNanIface iface = mHal.getWifiNanIface();
    518         if (iface == null) {
    519             Log.e(TAG, "disable: null interface");
    520             return false;
    521         }
    522 
    523         try {
    524             WifiStatus status = iface.disableRequest(transactionId);
    525             if (status.code == WifiStatusCode.SUCCESS) {
    526                 return true;
    527             } else {
    528                 Log.e(TAG, "disable: error: " + statusString(status));
    529                 return false;
    530             }
    531         } catch (RemoteException e) {
    532             Log.e(TAG, "disable: exception: " + e);
    533             return false;
    534         }
    535     }
    536 
    537     /**
    538      * Start or modify a service publish session.
    539      *
    540      * @param transactionId transactionId Transaction ID for the transaction -
    541      *            used in the async callback to match with the original request.
    542      * @param publishId ID of the requested session - 0 to request a new publish
    543      *            session.
    544      * @param publishConfig Configuration of the discovery session.
    545      */
    546     public boolean publish(short transactionId, byte publishId, PublishConfig publishConfig) {
    547         if (mDbg) {
    548             Log.d(TAG, "publish: transactionId=" + transactionId + ", publishId=" + publishId
    549                     + ", config=" + publishConfig);
    550         }
    551         recordTransactionId(transactionId);
    552 
    553         IWifiNanIface iface = mHal.getWifiNanIface();
    554         if (iface == null) {
    555             Log.e(TAG, "publish: null interface");
    556             return false;
    557         }
    558 
    559         NanPublishRequest req = new NanPublishRequest();
    560         req.baseConfigs.sessionId = publishId;
    561         req.baseConfigs.ttlSec = (short) publishConfig.mTtlSec;
    562         req.baseConfigs.discoveryWindowPeriod = 1;
    563         req.baseConfigs.discoveryCount = 0;
    564         convertNativeByteArrayToArrayList(publishConfig.mServiceName, req.baseConfigs.serviceName);
    565         req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_NEVER;
    566         convertNativeByteArrayToArrayList(publishConfig.mServiceSpecificInfo,
    567                 req.baseConfigs.serviceSpecificInfo);
    568         convertNativeByteArrayToArrayList(publishConfig.mMatchFilter,
    569                 publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED
    570                         ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter);
    571         req.baseConfigs.useRssiThreshold = false;
    572         req.baseConfigs.disableDiscoveryTerminationIndication =
    573                 !publishConfig.mEnableTerminateNotification;
    574         req.baseConfigs.disableMatchExpirationIndication = true;
    575         req.baseConfigs.disableFollowupReceivedIndication = false;
    576 
    577         req.autoAcceptDataPathRequests = false;
    578 
    579         req.baseConfigs.rangingRequired = publishConfig.mEnableRanging;
    580 
    581         // TODO: configure security
    582         req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN;
    583 
    584         req.publishType = publishConfig.mPublishType;
    585         req.txType = NanTxType.BROADCAST;
    586 
    587         try {
    588             WifiStatus status = iface.startPublishRequest(transactionId, req);
    589             if (status.code == WifiStatusCode.SUCCESS) {
    590                 return true;
    591             } else {
    592                 Log.e(TAG, "publish: error: " + statusString(status));
    593                 return false;
    594             }
    595         } catch (RemoteException e) {
    596             Log.e(TAG, "publish: exception: " + e);
    597             return false;
    598         }
    599     }
    600 
    601     /**
    602      * Start or modify a service subscription session.
    603      *
    604      * @param transactionId transactionId Transaction ID for the transaction -
    605      *            used in the async callback to match with the original request.
    606      * @param subscribeId ID of the requested session - 0 to request a new
    607      *            subscribe session.
    608      * @param subscribeConfig Configuration of the discovery session.
    609      */
    610     public boolean subscribe(short transactionId, byte subscribeId,
    611             SubscribeConfig subscribeConfig) {
    612         if (mDbg) {
    613             Log.d(TAG, "subscribe: transactionId=" + transactionId + ", subscribeId=" + subscribeId
    614                     + ", config=" + subscribeConfig);
    615         }
    616         recordTransactionId(transactionId);
    617 
    618         IWifiNanIface iface = mHal.getWifiNanIface();
    619         if (iface == null) {
    620             Log.e(TAG, "subscribe: null interface");
    621             return false;
    622         }
    623 
    624         NanSubscribeRequest req = new NanSubscribeRequest();
    625         req.baseConfigs.sessionId = subscribeId;
    626         req.baseConfigs.ttlSec = (short) subscribeConfig.mTtlSec;
    627         req.baseConfigs.discoveryWindowPeriod = 1;
    628         req.baseConfigs.discoveryCount = 0;
    629         convertNativeByteArrayToArrayList(subscribeConfig.mServiceName,
    630                 req.baseConfigs.serviceName);
    631         req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_ONCE;
    632         convertNativeByteArrayToArrayList(subscribeConfig.mServiceSpecificInfo,
    633                 req.baseConfigs.serviceSpecificInfo);
    634         convertNativeByteArrayToArrayList(subscribeConfig.mMatchFilter,
    635                 subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE
    636                         ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter);
    637         req.baseConfigs.useRssiThreshold = false;
    638         req.baseConfigs.disableDiscoveryTerminationIndication =
    639                 !subscribeConfig.mEnableTerminateNotification;
    640         req.baseConfigs.disableMatchExpirationIndication = true;
    641         req.baseConfigs.disableFollowupReceivedIndication = false;
    642 
    643         req.baseConfigs.rangingRequired =
    644                 subscribeConfig.mMinDistanceMmSet || subscribeConfig.mMaxDistanceMmSet;
    645         req.baseConfigs.configRangingIndications = 0;
    646         // TODO: b/69428593 remove correction factors once HAL converted from CM to MM
    647         if (subscribeConfig.mMinDistanceMmSet) {
    648             req.baseConfigs.distanceEgressCm = (short) Math.min(
    649                     subscribeConfig.mMinDistanceMm / 10, Short.MAX_VALUE);
    650             req.baseConfigs.configRangingIndications |= NanRangingIndication.EGRESS_MET_MASK;
    651         }
    652         if (subscribeConfig.mMaxDistanceMmSet) {
    653             req.baseConfigs.distanceIngressCm = (short) Math.min(
    654                     subscribeConfig.mMaxDistanceMm / 10, Short.MAX_VALUE);
    655             req.baseConfigs.configRangingIndications |= NanRangingIndication.INGRESS_MET_MASK;
    656         }
    657 
    658         // TODO: configure security
    659         req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN;
    660 
    661         req.subscribeType = subscribeConfig.mSubscribeType;
    662 
    663         try {
    664             WifiStatus status = iface.startSubscribeRequest(transactionId, req);
    665             if (status.code == WifiStatusCode.SUCCESS) {
    666                 return true;
    667             } else {
    668                 Log.e(TAG, "subscribe: error: " + statusString(status));
    669                 return false;
    670             }
    671         } catch (RemoteException e) {
    672             Log.e(TAG, "subscribe: exception: " + e);
    673             return false;
    674         }
    675     }
    676 
    677     /**
    678      * Send a message through an existing discovery session.
    679      *
    680      * @param transactionId transactionId Transaction ID for the transaction -
    681      *            used in the async callback to match with the original request.
    682      * @param pubSubId ID of the existing publish/subscribe session.
    683      * @param requestorInstanceId ID of the peer to communicate with - obtained
    684      *            through a previous discovery (match) operation with that peer.
    685      * @param dest MAC address of the peer to communicate with - obtained
    686      *            together with requestorInstanceId.
    687      * @param message Message.
    688      * @param messageId Arbitary integer from host (not sent to HAL - useful for
    689      *                  testing/debugging at this level)
    690      */
    691     public boolean sendMessage(short transactionId, byte pubSubId, int requestorInstanceId,
    692             byte[] dest, byte[] message, int messageId) {
    693         if (mDbg) {
    694             Log.d(TAG,
    695                     "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId
    696                             + ", requestorInstanceId=" + requestorInstanceId + ", dest="
    697                             + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" + messageId
    698                             + ", message=" + (message == null ? "<null>"
    699                             : HexEncoding.encode(message)) + ", message.length=" + (message == null
    700                             ? 0 : message.length));
    701         }
    702         recordTransactionId(transactionId);
    703 
    704         IWifiNanIface iface = mHal.getWifiNanIface();
    705         if (iface == null) {
    706             Log.e(TAG, "sendMessage: null interface");
    707             return false;
    708         }
    709 
    710         NanTransmitFollowupRequest req = new NanTransmitFollowupRequest();
    711         req.discoverySessionId = pubSubId;
    712         req.peerId = requestorInstanceId;
    713         copyArray(dest, req.addr);
    714         req.isHighPriority = false;
    715         req.shouldUseDiscoveryWindow = true;
    716         convertNativeByteArrayToArrayList(message, req.serviceSpecificInfo);
    717         req.disableFollowupResultIndication = false;
    718 
    719         try {
    720             WifiStatus status = iface.transmitFollowupRequest(transactionId, req);
    721             if (status.code == WifiStatusCode.SUCCESS) {
    722                 return true;
    723             } else {
    724                 Log.e(TAG, "sendMessage: error: " + statusString(status));
    725                 return false;
    726             }
    727         } catch (RemoteException e) {
    728             Log.e(TAG, "sendMessage: exception: " + e);
    729             return false;
    730         }
    731     }
    732 
    733     /**
    734      * Terminate a publish discovery session.
    735      *
    736      * @param transactionId transactionId Transaction ID for the transaction -
    737      *            used in the async callback to match with the original request.
    738      * @param pubSubId ID of the publish/subscribe session - obtained when
    739      *            creating a session.
    740      */
    741     public boolean stopPublish(short transactionId, byte pubSubId) {
    742         if (mDbg) {
    743             Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
    744         }
    745         recordTransactionId(transactionId);
    746 
    747         IWifiNanIface iface = mHal.getWifiNanIface();
    748         if (iface == null) {
    749             Log.e(TAG, "stopPublish: null interface");
    750             return false;
    751         }
    752 
    753         try {
    754             WifiStatus status = iface.stopPublishRequest(transactionId, pubSubId);
    755             if (status.code == WifiStatusCode.SUCCESS) {
    756                 return true;
    757             } else {
    758                 Log.e(TAG, "stopPublish: error: " + statusString(status));
    759                 return false;
    760             }
    761         } catch (RemoteException e) {
    762             Log.e(TAG, "stopPublish: exception: " + e);
    763             return false;
    764         }
    765     }
    766 
    767     /**
    768      * Terminate a subscribe discovery session.
    769      *
    770      * @param transactionId transactionId Transaction ID for the transaction -
    771      *            used in the async callback to match with the original request.
    772      * @param pubSubId ID of the publish/subscribe session - obtained when
    773      *            creating a session.
    774      */
    775     public boolean stopSubscribe(short transactionId, byte pubSubId) {
    776         if (mDbg) {
    777             Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
    778         }
    779         recordTransactionId(transactionId);
    780 
    781         IWifiNanIface iface = mHal.getWifiNanIface();
    782         if (iface == null) {
    783             Log.e(TAG, "stopSubscribe: null interface");
    784             return false;
    785         }
    786 
    787         try {
    788             WifiStatus status = iface.stopSubscribeRequest(transactionId, pubSubId);
    789             if (status.code == WifiStatusCode.SUCCESS) {
    790                 return true;
    791             } else {
    792                 Log.e(TAG, "stopSubscribe: error: " + statusString(status));
    793                 return false;
    794             }
    795         } catch (RemoteException e) {
    796             Log.e(TAG, "stopSubscribe: exception: " + e);
    797             return false;
    798         }
    799     }
    800 
    801     /**
    802      * Create a Aware network interface. This only creates the Linux interface - it doesn't actually
    803      * create the data connection.
    804      *
    805      * @param transactionId Transaction ID for the transaction - used in the async callback to
    806      *                      match with the original request.
    807      * @param interfaceName The name of the interface, e.g. "aware0".
    808      */
    809     public boolean createAwareNetworkInterface(short transactionId, String interfaceName) {
    810         if (mDbg) {
    811             Log.v(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", "
    812                     + "interfaceName=" + interfaceName);
    813         }
    814         recordTransactionId(transactionId);
    815 
    816         IWifiNanIface iface = mHal.getWifiNanIface();
    817         if (iface == null) {
    818             Log.e(TAG, "createAwareNetworkInterface: null interface");
    819             return false;
    820         }
    821 
    822         try {
    823             WifiStatus status = iface.createDataInterfaceRequest(transactionId, interfaceName);
    824             if (status.code == WifiStatusCode.SUCCESS) {
    825                 return true;
    826             } else {
    827                 Log.e(TAG, "createAwareNetworkInterface: error: " + statusString(status));
    828                 return false;
    829             }
    830         } catch (RemoteException e) {
    831             Log.e(TAG, "createAwareNetworkInterface: exception: " + e);
    832             return false;
    833         }
    834     }
    835 
    836     /**
    837      * Deletes a Aware network interface. The data connection can (should?) be torn down previously.
    838      *
    839      * @param transactionId Transaction ID for the transaction - used in the async callback to
    840      *                      match with the original request.
    841      * @param interfaceName The name of the interface, e.g. "aware0".
    842      */
    843     public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) {
    844         if (mDbg) {
    845             Log.v(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", "
    846                     + "interfaceName=" + interfaceName);
    847         }
    848         recordTransactionId(transactionId);
    849 
    850         IWifiNanIface iface = mHal.getWifiNanIface();
    851         if (iface == null) {
    852             Log.e(TAG, "deleteAwareNetworkInterface: null interface");
    853             return false;
    854         }
    855 
    856         try {
    857             WifiStatus status = iface.deleteDataInterfaceRequest(transactionId, interfaceName);
    858             if (status.code == WifiStatusCode.SUCCESS) {
    859                 return true;
    860             } else {
    861                 Log.e(TAG, "deleteAwareNetworkInterface: error: " + statusString(status));
    862                 return false;
    863             }
    864         } catch (RemoteException e) {
    865             Log.e(TAG, "deleteAwareNetworkInterface: exception: " + e);
    866             return false;
    867         }
    868     }
    869 
    870     /**
    871      * Initiates setting up a data-path between device and peer. Security is provided by either
    872      * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up.
    873      *
    874      * @param transactionId      Transaction ID for the transaction - used in the async callback to
    875      *                           match with the original request.
    876      * @param peerId             ID of the peer ID to associate the data path with. A value of 0
    877      *                           indicates that not associated with an existing session.
    878      * @param channelRequestType Indicates whether the specified channel is available, if available
    879      *                           requested or forced (resulting in failure if cannot be
    880      *                           accommodated).
    881      * @param channel            The channel on which to set up the data-path.
    882      * @param peer               The MAC address of the peer to create a connection with.
    883      * @param interfaceName      The interface on which to create the data connection.
    884      * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path.
    885      * @param passphrase  Passphrase for the data-path.
    886      * @param capabilities The capabilities of the firmware.
    887      */
    888     public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType,
    889             int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase,
    890             boolean isOutOfBand, Capabilities capabilities) {
    891         if (mDbg) {
    892             Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId
    893                     + ", channelRequestType=" + channelRequestType + ", channel=" + channel
    894                     + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName="
    895                     + interfaceName);
    896         }
    897         recordTransactionId(transactionId);
    898 
    899         IWifiNanIface iface = mHal.getWifiNanIface();
    900         if (iface == null) {
    901             Log.e(TAG, "initiateDataPath: null interface");
    902             return false;
    903         }
    904 
    905         if (capabilities == null) {
    906             Log.e(TAG, "initiateDataPath: null capabilities");
    907             return false;
    908         }
    909 
    910         NanInitiateDataPathRequest req = new NanInitiateDataPathRequest();
    911         req.peerId = peerId;
    912         copyArray(peer, req.peerDiscMacAddr);
    913         req.channelRequestType = channelRequestType;
    914         req.channel = channel;
    915         req.ifaceName = interfaceName;
    916         req.securityConfig.securityType = NanDataPathSecurityType.OPEN;
    917         if (pmk != null && pmk.length != 0) {
    918             req.securityConfig.cipherType = getStrongestCipherSuiteType(
    919                     capabilities.supportedCipherSuites);
    920             req.securityConfig.securityType = NanDataPathSecurityType.PMK;
    921             copyArray(pmk, req.securityConfig.pmk);
    922         }
    923         if (passphrase != null && passphrase.length() != 0) {
    924             req.securityConfig.cipherType = getStrongestCipherSuiteType(
    925                     capabilities.supportedCipherSuites);
    926             req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE;
    927             convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase);
    928         }
    929 
    930         if (req.securityConfig.securityType != NanDataPathSecurityType.OPEN && isOutOfBand) {
    931             convertNativeByteArrayToArrayList(
    932                     SERVICE_NAME_FOR_OOB_DATA_PATH.getBytes(StandardCharsets.UTF_8),
    933                     req.serviceNameOutOfBand);
    934         }
    935 
    936         try {
    937             WifiStatus status = iface.initiateDataPathRequest(transactionId, req);
    938             if (status.code == WifiStatusCode.SUCCESS) {
    939                 return true;
    940             } else {
    941                 Log.e(TAG, "initiateDataPath: error: " + statusString(status));
    942                 return false;
    943             }
    944         } catch (RemoteException e) {
    945             Log.e(TAG, "initiateDataPath: exception: " + e);
    946             return false;
    947         }
    948     }
    949 
    950     /**
    951      * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not
    952      * both) - if both are null then an open (unencrypted) link is set up.
    953      *
    954      * @param transactionId Transaction ID for the transaction - used in the async callback to
    955      *                      match with the original request.
    956      * @param accept Accept (true) or reject (false) the original call.
    957      * @param ndpId The NDP (Aware data path) ID. Obtained from the request callback.
    958      * @param interfaceName The interface on which the data path will be setup. Obtained from the
    959      *                      request callback.
    960      * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path.
    961      * @param passphrase  Passphrase for the data-path.
    962      * @param isOutOfBand Is the data-path out-of-band (i.e. without a corresponding Aware discovery
    963      *                    session).
    964      * @param capabilities The capabilities of the firmware.
    965      */
    966     public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId,
    967             String interfaceName, byte[] pmk, String passphrase, boolean isOutOfBand,
    968             Capabilities capabilities) {
    969         if (mDbg) {
    970             Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept="
    971                     + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName);
    972         }
    973         recordTransactionId(transactionId);
    974 
    975         IWifiNanIface iface = mHal.getWifiNanIface();
    976         if (iface == null) {
    977             Log.e(TAG, "respondToDataPathRequest: null interface");
    978             return false;
    979         }
    980 
    981         if (capabilities == null) {
    982             Log.e(TAG, "initiateDataPath: null capabilities");
    983             return false;
    984         }
    985 
    986         NanRespondToDataPathIndicationRequest req = new NanRespondToDataPathIndicationRequest();
    987         req.acceptRequest = accept;
    988         req.ndpInstanceId = ndpId;
    989         req.ifaceName = interfaceName;
    990         req.securityConfig.securityType = NanDataPathSecurityType.OPEN;
    991         if (pmk != null && pmk.length != 0) {
    992             req.securityConfig.cipherType = getStrongestCipherSuiteType(
    993                     capabilities.supportedCipherSuites);
    994             req.securityConfig.securityType = NanDataPathSecurityType.PMK;
    995             copyArray(pmk, req.securityConfig.pmk);
    996         }
    997         if (passphrase != null && passphrase.length() != 0) {
    998             req.securityConfig.cipherType = getStrongestCipherSuiteType(
    999                     capabilities.supportedCipherSuites);
   1000             req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE;
   1001             convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase);
   1002         }
   1003 
   1004         if (req.securityConfig.securityType != NanDataPathSecurityType.OPEN && isOutOfBand) {
   1005             convertNativeByteArrayToArrayList(
   1006                     SERVICE_NAME_FOR_OOB_DATA_PATH.getBytes(StandardCharsets.UTF_8),
   1007                     req.serviceNameOutOfBand);
   1008         }
   1009 
   1010         try {
   1011             WifiStatus status = iface.respondToDataPathIndicationRequest(transactionId, req);
   1012             if (status.code == WifiStatusCode.SUCCESS) {
   1013                 return true;
   1014             } else {
   1015                 Log.e(TAG, "respondToDataPathRequest: error: " + statusString(status));
   1016                 return false;
   1017             }
   1018         } catch (RemoteException e) {
   1019             Log.e(TAG, "respondToDataPathRequest: exception: " + e);
   1020             return false;
   1021         }
   1022     }
   1023 
   1024     /**
   1025      * Terminate an existing data-path (does not delete the interface).
   1026      *
   1027      * @param transactionId Transaction ID for the transaction - used in the async callback to
   1028      *                      match with the original request.
   1029      * @param ndpId The NDP (Aware data path) ID to be terminated.
   1030      */
   1031     public boolean endDataPath(short transactionId, int ndpId) {
   1032         if (mDbg) {
   1033             Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId);
   1034         }
   1035         recordTransactionId(transactionId);
   1036 
   1037         IWifiNanIface iface = mHal.getWifiNanIface();
   1038         if (iface == null) {
   1039             Log.e(TAG, "endDataPath: null interface");
   1040             return false;
   1041         }
   1042 
   1043         try {
   1044             WifiStatus status = iface.terminateDataPathRequest(transactionId, ndpId);
   1045             if (status.code == WifiStatusCode.SUCCESS) {
   1046                 return true;
   1047             } else {
   1048                 Log.e(TAG, "endDataPath: error: " + statusString(status));
   1049                 return false;
   1050             }
   1051         } catch (RemoteException e) {
   1052             Log.e(TAG, "endDataPath: exception: " + e);
   1053             return false;
   1054         }
   1055     }
   1056 
   1057 
   1058     // utilities
   1059 
   1060     /**
   1061      * Update the NAN configuration to reflect the current power settings.
   1062      */
   1063     private void updateConfigForPowerSettings(NanConfigRequest req,
   1064             NanConfigRequestSupplemental configSupplemental12, boolean isInteractive,
   1065             boolean isIdle) {
   1066         String key = POWER_PARAM_DEFAULT_KEY;
   1067         if (isIdle) {
   1068             key = POWER_PARAM_IDLE_KEY;
   1069         } else if (!isInteractive) {
   1070             key = POWER_PARAM_INACTIVE_KEY;
   1071         }
   1072 
   1073         updateSingleConfigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ],
   1074                 mSettablePowerParameters.get(key).get(PARAM_DW_5GHZ));
   1075         updateSingleConfigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ],
   1076                 mSettablePowerParameters.get(key).get(PARAM_DW_24GHZ));
   1077 
   1078         configSupplemental12.discoveryBeaconIntervalMs = mSettablePowerParameters.get(key).get(
   1079                 PARAM_DISCOVERY_BEACON_INTERVAL_MS);
   1080         configSupplemental12.numberOfSpatialStreamsInDiscovery = mSettablePowerParameters.get(
   1081                 key).get(PARAM_NUM_SS_IN_DISCOVERY);
   1082         configSupplemental12.enableDiscoveryWindowEarlyTermination = mSettablePowerParameters.get(
   1083                 key).get(PARAM_ENABLE_DW_EARLY_TERM) != 0;
   1084     }
   1085 
   1086     private void updateSingleConfigForPowerSettings(NanBandSpecificConfig cfg, int override) {
   1087         if (override != -1) {
   1088             cfg.validDiscoveryWindowIntervalVal = true;
   1089             cfg.discoveryWindowIntervalVal = (byte) override;
   1090         }
   1091     }
   1092 
   1093     /**
   1094      * Returns the strongest supported cipher suite.
   1095      *
   1096      * Baseline is very simple: 256 > 128 > 0.
   1097      */
   1098     private int getStrongestCipherSuiteType(int supportedCipherSuites) {
   1099         if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_256_MASK) != 0) {
   1100             return NanCipherSuiteType.SHARED_KEY_256_MASK;
   1101         }
   1102         if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_128_MASK) != 0) {
   1103             return NanCipherSuiteType.SHARED_KEY_128_MASK;
   1104         }
   1105         return NanCipherSuiteType.NONE;
   1106     }
   1107 
   1108     /**
   1109      * Converts a byte[] to an ArrayList<Byte>. Fills in the entries of the 'to' array if
   1110      * provided (non-null), otherwise creates and returns a new ArrayList<>.
   1111      *
   1112      * @param from The input byte[] to convert from.
   1113      * @param to An optional ArrayList<> to fill in from 'from'.
   1114      *
   1115      * @return A newly allocated ArrayList<> if 'to' is null, otherwise null.
   1116      */
   1117     private ArrayList<Byte> convertNativeByteArrayToArrayList(byte[] from, ArrayList<Byte> to) {
   1118         if (from == null) {
   1119             from = new byte[0];
   1120         }
   1121 
   1122         if (to == null) {
   1123             to = new ArrayList<>(from.length);
   1124         } else {
   1125             to.ensureCapacity(from.length);
   1126         }
   1127         for (int i = 0; i < from.length; ++i) {
   1128             to.add(from[i]);
   1129         }
   1130         return to;
   1131     }
   1132 
   1133     private void copyArray(byte[] from, byte[] to) {
   1134         if (from == null || to == null || from.length != to.length) {
   1135             Log.e(TAG, "copyArray error: from=" + from + ", to=" + to);
   1136             return;
   1137         }
   1138         for (int i = 0; i < from.length; ++i) {
   1139             to[i] = from[i];
   1140         }
   1141     }
   1142 
   1143     private static String statusString(WifiStatus status) {
   1144         if (status == null) {
   1145             return "status=null";
   1146         }
   1147         StringBuilder sb = new StringBuilder();
   1148         sb.append(status.code).append(" (").append(status.description).append(")");
   1149         return sb.toString();
   1150     }
   1151 
   1152     /**
   1153      * Dump the internal state of the class.
   1154      */
   1155     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1156         pw.println("WifiAwareNativeApi:");
   1157         pw.println("  mSettableParameters: " + mSettableParameters);
   1158         mHal.dump(fd, pw, args);
   1159     }
   1160 }
   1161