WifiAwareNativeApi.java revision 16b00750e1d3c41ce9b4ccae9f07e0586e8ca2d0
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 17package com.android.server.wifi.aware; 18 19import android.hardware.wifi.V1_0.IWifiNanIface; 20import android.hardware.wifi.V1_0.NanBandIndex; 21import android.hardware.wifi.V1_0.NanBandSpecificConfig; 22import android.hardware.wifi.V1_0.NanCipherSuiteType; 23import android.hardware.wifi.V1_0.NanConfigRequest; 24import android.hardware.wifi.V1_0.NanDataPathSecurityType; 25import android.hardware.wifi.V1_0.NanEnableRequest; 26import android.hardware.wifi.V1_0.NanInitiateDataPathRequest; 27import android.hardware.wifi.V1_0.NanMatchAlg; 28import android.hardware.wifi.V1_0.NanPublishRequest; 29import android.hardware.wifi.V1_0.NanRespondToDataPathIndicationRequest; 30import android.hardware.wifi.V1_0.NanSubscribeRequest; 31import android.hardware.wifi.V1_0.NanTransmitFollowupRequest; 32import android.hardware.wifi.V1_0.NanTxType; 33import android.hardware.wifi.V1_0.WifiStatus; 34import android.hardware.wifi.V1_0.WifiStatusCode; 35import android.net.wifi.aware.ConfigRequest; 36import android.net.wifi.aware.PublishConfig; 37import android.net.wifi.aware.SubscribeConfig; 38import android.os.RemoteException; 39import android.util.Log; 40 41import libcore.util.HexEncoding; 42 43import java.io.FileDescriptor; 44import java.io.PrintWriter; 45import java.util.ArrayList; 46 47/** 48 * Translates Wi-Fi Aware requests from the framework to the HAL (HIDL). 49 * 50 * Delegates the management of the NAN interface to WifiAwareNativeManager. 51 */ 52public class WifiAwareNativeApi { 53 private static final String TAG = "WifiAwareNativeApi"; 54 private static final boolean DBG = false; 55 private static final boolean VDBG = false; // STOPSHIP if true 56 57 private final WifiAwareNativeManager mHal; 58 59 public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) { 60 mHal = wifiAwareNativeManager; 61 } 62 63 /** 64 * Query the firmware's capabilities. 65 * 66 * @param transactionId Transaction ID for the transaction - used in the async callback to 67 * match with the original request. 68 */ 69 public boolean getCapabilities(short transactionId) { 70 if (VDBG) Log.v(TAG, "getCapabilities: transactionId=" + transactionId); 71 72 IWifiNanIface iface = mHal.getWifiNanIface(); 73 if (iface == null) { 74 Log.e(TAG, "getCapabilities: null interface"); 75 return false; 76 } 77 78 try { 79 WifiStatus status = iface.getCapabilitiesRequest(transactionId); 80 if (status.code == WifiStatusCode.SUCCESS) { 81 return true; 82 } else { 83 Log.e(TAG, "getCapabilities: error: " + statusString(status)); 84 return false; 85 } 86 } catch (RemoteException e) { 87 Log.e(TAG, "getCapabilities: exception: " + e); 88 return false; 89 } 90 } 91 92 /** 93 * Enable and configure Aware. 94 * 95 * @param transactionId Transaction ID for the transaction - used in the 96 * async callback to match with the original request. 97 * @param configRequest Requested Aware configuration. 98 * @param notifyIdentityChange Indicates whether or not to get address change callbacks. 99 * @param initialConfiguration Specifies whether initial configuration 100 * (true) or an update (false) to the configuration. 101 */ 102 public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, 103 boolean notifyIdentityChange, boolean initialConfiguration) { 104 if (VDBG) { 105 Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest=" 106 + configRequest + ", notifyIdentityChange=" + notifyIdentityChange 107 + ", initialConfiguration=" + initialConfiguration); 108 } 109 110 IWifiNanIface iface = mHal.getWifiNanIface(); 111 if (iface == null) { 112 Log.e(TAG, "enableAndConfigure: null interface"); 113 return false; 114 } 115 116 try { 117 WifiStatus status; 118 if (initialConfiguration) { 119 // translate framework to HIDL configuration 120 NanEnableRequest req = new NanEnableRequest(); 121 122 req.operateInBand[NanBandIndex.NAN_BAND_24GHZ] = true; 123 req.operateInBand[NanBandIndex.NAN_BAND_5GHZ] = configRequest.mSupport5gBand; 124 req.hopCountMax = 2; 125 req.configParams.masterPref = (byte) configRequest.mMasterPreference; 126 req.configParams.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 127 req.configParams.disableStartedClusterIndication = !notifyIdentityChange; 128 req.configParams.disableJoinedClusterIndication = !notifyIdentityChange; 129 req.configParams.includePublishServiceIdsInBeacon = true; 130 req.configParams.numberOfPublishServiceIdsInBeacon = 0; 131 req.configParams.includeSubscribeServiceIdsInBeacon = true; 132 req.configParams.numberOfSubscribeServiceIdsInBeacon = 0; 133 req.configParams.rssiWindowSize = 8; 134 req.configParams.macAddressRandomizationIntervalSec = 1800; 135 136 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 137 config24.rssiClose = 60; 138 config24.rssiMiddle = 70; 139 config24.rssiCloseProximity = 60; 140 config24.dwellTimeMs = (byte) 200; 141 config24.scanPeriodSec = 20; 142 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 143 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 144 config24.validDiscoveryWindowIntervalVal = false; 145 } else { 146 config24.validDiscoveryWindowIntervalVal = true; 147 config24.discoveryWindowIntervalVal = 148 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 149 .NAN_BAND_24GHZ]; 150 } 151 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 152 153 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 154 config5.rssiClose = 60; 155 config5.rssiMiddle = 75; 156 config5.rssiCloseProximity = 60; 157 config5.dwellTimeMs = (byte) 200; 158 config5.scanPeriodSec = 20; 159 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 160 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 161 config5.validDiscoveryWindowIntervalVal = false; 162 } else { 163 config5.validDiscoveryWindowIntervalVal = true; 164 config5.discoveryWindowIntervalVal = 165 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 166 .NAN_BAND_5GHZ]; 167 } 168 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 169 170 req.debugConfigs.validClusterIdVals = true; 171 req.debugConfigs.clusterIdTopRangeVal = (short) configRequest.mClusterHigh; 172 req.debugConfigs.clusterIdBottomRangeVal = (short) configRequest.mClusterLow; 173 req.debugConfigs.validIntfAddrVal = false; 174 req.debugConfigs.validOuiVal = false; 175 req.debugConfigs.ouiVal = 0; 176 req.debugConfigs.validRandomFactorForceVal = false; 177 req.debugConfigs.randomFactorForceVal = 0; 178 req.debugConfigs.validHopCountForceVal = false; 179 req.debugConfigs.hopCountForceVal = 0; 180 req.debugConfigs.validDiscoveryChannelVal = false; 181 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_24GHZ] = 0; 182 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_5GHZ] = 0; 183 req.debugConfigs.validUseBeaconsInBandVal = false; 184 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 185 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 186 req.debugConfigs.validUseSdfInBandVal = false; 187 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 188 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 189 190 status = iface.enableRequest(transactionId, req); 191 } else { 192 NanConfigRequest req = new NanConfigRequest(); 193 req.masterPref = (byte) configRequest.mMasterPreference; 194 req.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 195 req.disableStartedClusterIndication = !notifyIdentityChange; 196 req.disableJoinedClusterIndication = !notifyIdentityChange; 197 req.includePublishServiceIdsInBeacon = true; 198 req.numberOfPublishServiceIdsInBeacon = 0; 199 req.includeSubscribeServiceIdsInBeacon = true; 200 req.numberOfSubscribeServiceIdsInBeacon = 0; 201 req.rssiWindowSize = 8; 202 req.macAddressRandomizationIntervalSec = 1800; 203 204 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 205 config24.rssiClose = 60; 206 config24.rssiMiddle = 70; 207 config24.rssiCloseProximity = 60; 208 config24.dwellTimeMs = (byte) 200; 209 config24.scanPeriodSec = 20; 210 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 211 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 212 config24.validDiscoveryWindowIntervalVal = false; 213 } else { 214 config24.validDiscoveryWindowIntervalVal = true; 215 config24.discoveryWindowIntervalVal = 216 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 217 .NAN_BAND_24GHZ]; 218 } 219 req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 220 221 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 222 config5.rssiClose = 60; 223 config5.rssiMiddle = 75; 224 config5.rssiCloseProximity = 60; 225 config5.dwellTimeMs = (byte) 200; 226 config5.scanPeriodSec = 20; 227 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 228 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 229 config5.validDiscoveryWindowIntervalVal = false; 230 } else { 231 config5.validDiscoveryWindowIntervalVal = true; 232 config5.discoveryWindowIntervalVal = 233 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 234 .NAN_BAND_5GHZ]; 235 } 236 req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 237 238 status = iface.configRequest(transactionId, req); 239 } 240 if (status.code == WifiStatusCode.SUCCESS) { 241 return true; 242 } else { 243 Log.e(TAG, "enableAndConfigure: error: " + statusString(status)); 244 return false; 245 } 246 } catch (RemoteException e) { 247 Log.e(TAG, "enableAndConfigure: exception: " + e); 248 return false; 249 } 250 } 251 252 /** 253 * Disable Aware. 254 * 255 * @param transactionId transactionId Transaction ID for the transaction - 256 * used in the async callback to match with the original request. 257 */ 258 public boolean disable(short transactionId) { 259 if (VDBG) Log.d(TAG, "disable"); 260 261 IWifiNanIface iface = mHal.getWifiNanIface(); 262 if (iface == null) { 263 Log.e(TAG, "disable: null interface"); 264 return false; 265 } 266 267 try { 268 WifiStatus status = iface.disableRequest(transactionId); 269 if (status.code == WifiStatusCode.SUCCESS) { 270 return true; 271 } else { 272 Log.e(TAG, "disable: error: " + statusString(status)); 273 return false; 274 } 275 } catch (RemoteException e) { 276 Log.e(TAG, "disable: exception: " + e); 277 return false; 278 } 279 } 280 281 /** 282 * Start or modify a service publish session. 283 * 284 * @param transactionId transactionId Transaction ID for the transaction - 285 * used in the async callback to match with the original request. 286 * @param publishId ID of the requested session - 0 to request a new publish 287 * session. 288 * @param publishConfig Configuration of the discovery session. 289 */ 290 public boolean publish(short transactionId, int publishId, PublishConfig publishConfig) { 291 if (VDBG) { 292 Log.d(TAG, "publish: transactionId=" + transactionId + ", config=" + publishConfig); 293 } 294 295 IWifiNanIface iface = mHal.getWifiNanIface(); 296 if (iface == null) { 297 Log.e(TAG, "publish: null interface"); 298 return false; 299 } 300 301 NanPublishRequest req = new NanPublishRequest(); 302 req.baseConfigs.sessionId = 0; 303 req.baseConfigs.ttlSec = (short) publishConfig.mTtlSec; 304 req.baseConfigs.discoveryWindowPeriod = 1; 305 req.baseConfigs.discoveryCount = 0; 306 convertNativeByteArrayToArrayList(publishConfig.mServiceName, req.baseConfigs.serviceName); 307 // TODO: what's the right value on publish? 308 req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_ONCE; 309 convertNativeByteArrayToArrayList(publishConfig.mServiceSpecificInfo, 310 req.baseConfigs.serviceSpecificInfo); 311 convertNativeByteArrayToArrayList(publishConfig.mMatchFilter, 312 publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED 313 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 314 req.baseConfigs.useRssiThreshold = false; 315 req.baseConfigs.disableDiscoveryTerminationIndication = 316 !publishConfig.mEnableTerminateNotification; 317 req.baseConfigs.disableMatchExpirationIndication = true; 318 req.baseConfigs.disableFollowupReceivedIndication = false; 319 320 // TODO: configure ranging and security 321 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 322 req.baseConfigs.rangingRequired = false; 323 req.autoAcceptDataPathRequests = false; 324 325 req.publishType = publishConfig.mPublishType; 326 req.txType = NanTxType.BROADCAST; 327 328 try { 329 WifiStatus status = iface.startPublishRequest(transactionId, req); 330 if (status.code == WifiStatusCode.SUCCESS) { 331 return true; 332 } else { 333 Log.e(TAG, "publish: error: " + statusString(status)); 334 return false; 335 } 336 } catch (RemoteException e) { 337 Log.e(TAG, "publish: exception: " + e); 338 return false; 339 } 340 } 341 342 /** 343 * Start or modify a service subscription session. 344 * 345 * @param transactionId transactionId Transaction ID for the transaction - 346 * used in the async callback to match with the original request. 347 * @param subscribeId ID of the requested session - 0 to request a new 348 * subscribe session. 349 * @param subscribeConfig Configuration of the discovery session. 350 */ 351 public boolean subscribe(short transactionId, int subscribeId, 352 SubscribeConfig subscribeConfig) { 353 if (VDBG) { 354 Log.d(TAG, "subscribe: transactionId=" + transactionId + ", config=" + subscribeConfig); 355 } 356 357 IWifiNanIface iface = mHal.getWifiNanIface(); 358 if (iface == null) { 359 Log.e(TAG, "subscribe: null interface"); 360 return false; 361 } 362 363 NanSubscribeRequest req = new NanSubscribeRequest(); 364 req.baseConfigs.sessionId = 0; 365 req.baseConfigs.ttlSec = (short) subscribeConfig.mTtlSec; 366 req.baseConfigs.discoveryWindowPeriod = 1; 367 req.baseConfigs.discoveryCount = 0; 368 convertNativeByteArrayToArrayList(subscribeConfig.mServiceName, 369 req.baseConfigs.serviceName); 370 req.baseConfigs.discoveryMatchIndicator = subscribeConfig.mMatchStyle; 371 convertNativeByteArrayToArrayList(subscribeConfig.mServiceSpecificInfo, 372 req.baseConfigs.serviceSpecificInfo); 373 convertNativeByteArrayToArrayList(subscribeConfig.mMatchFilter, 374 subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE 375 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 376 req.baseConfigs.useRssiThreshold = false; 377 req.baseConfigs.disableDiscoveryTerminationIndication = 378 !subscribeConfig.mEnableTerminateNotification; 379 req.baseConfigs.disableMatchExpirationIndication = true; 380 req.baseConfigs.disableFollowupReceivedIndication = false; 381 382 // TODO: configure ranging and security 383 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 384 req.baseConfigs.rangingRequired = false; 385 386 req.subscribeType = subscribeConfig.mSubscribeType; 387 388 try { 389 WifiStatus status = iface.startSubscribeRequest(transactionId, req); 390 if (status.code == WifiStatusCode.SUCCESS) { 391 return true; 392 } else { 393 Log.e(TAG, "subscribe: error: " + statusString(status)); 394 return false; 395 } 396 } catch (RemoteException e) { 397 Log.e(TAG, "subscribe: exception: " + e); 398 return false; 399 } 400 } 401 402 /** 403 * Send a message through an existing discovery session. 404 * 405 * @param transactionId transactionId Transaction ID for the transaction - 406 * used in the async callback to match with the original request. 407 * @param pubSubId ID of the existing publish/subscribe session. 408 * @param requestorInstanceId ID of the peer to communicate with - obtained 409 * through a previous discovery (match) operation with that peer. 410 * @param dest MAC address of the peer to communicate with - obtained 411 * together with requestorInstanceId. 412 * @param message Message. 413 * @param messageId Arbitary integer from host (not sent to HAL - useful for 414 * testing/debugging at this level) 415 */ 416 public boolean sendMessage(short transactionId, int pubSubId, int requestorInstanceId, 417 byte[] dest, byte[] message, int messageId) { 418 if (VDBG) { 419 Log.d(TAG, 420 "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId 421 + ", requestorInstanceId=" + requestorInstanceId + ", dest=" 422 + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" 423 + messageId); 424 } 425 426 IWifiNanIface iface = mHal.getWifiNanIface(); 427 if (iface == null) { 428 Log.e(TAG, "sendMessage: null interface"); 429 return false; 430 } 431 432 NanTransmitFollowupRequest req = new NanTransmitFollowupRequest(); 433 req.discoverySessionId = (byte) pubSubId; 434 req.peerId = requestorInstanceId; 435 copyArray(dest, req.addr); 436 req.isHighPriority = false; 437 req.shouldUseDiscoveryWindow = true; 438 convertNativeByteArrayToArrayList(message, req.serviceSpecificInfo); 439 req.disableFollowupResultIndication = false; 440 441 try { 442 WifiStatus status = iface.transmitFollowupRequest(transactionId, req); 443 if (status.code == WifiStatusCode.SUCCESS) { 444 return true; 445 } else { 446 Log.e(TAG, "sendMessage: error: " + statusString(status)); 447 return false; 448 } 449 } catch (RemoteException e) { 450 Log.e(TAG, "sendMessage: exception: " + e); 451 return false; 452 } 453 } 454 455 /** 456 * Terminate a publish discovery session. 457 * 458 * @param transactionId transactionId Transaction ID for the transaction - 459 * used in the async callback to match with the original request. 460 * @param pubSubId ID of the publish/subscribe session - obtained when 461 * creating a session. 462 */ 463 public boolean stopPublish(short transactionId, int pubSubId) { 464 if (VDBG) { 465 Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 466 } 467 468 IWifiNanIface iface = mHal.getWifiNanIface(); 469 if (iface == null) { 470 Log.e(TAG, "stopPublish: null interface"); 471 return false; 472 } 473 474 try { 475 WifiStatus status = iface.stopPublishRequest(transactionId, (byte) pubSubId); 476 if (status.code == WifiStatusCode.SUCCESS) { 477 return true; 478 } else { 479 Log.e(TAG, "stopPublish: error: " + statusString(status)); 480 return false; 481 } 482 } catch (RemoteException e) { 483 Log.e(TAG, "stopPublish: exception: " + e); 484 return false; 485 } 486 } 487 488 /** 489 * Terminate a subscribe discovery session. 490 * 491 * @param transactionId transactionId Transaction ID for the transaction - 492 * used in the async callback to match with the original request. 493 * @param pubSubId ID of the publish/subscribe session - obtained when 494 * creating a session. 495 */ 496 public boolean stopSubscribe(short transactionId, int pubSubId) { 497 if (VDBG) { 498 Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 499 } 500 501 IWifiNanIface iface = mHal.getWifiNanIface(); 502 if (iface == null) { 503 Log.e(TAG, "stopSubscribe: null interface"); 504 return false; 505 } 506 507 try { 508 WifiStatus status = iface.stopSubscribeRequest(transactionId, (byte) pubSubId); 509 if (status.code == WifiStatusCode.SUCCESS) { 510 return true; 511 } else { 512 Log.e(TAG, "stopSubscribe: error: " + statusString(status)); 513 return false; 514 } 515 } catch (RemoteException e) { 516 Log.e(TAG, "stopSubscribe: exception: " + e); 517 return false; 518 } 519 } 520 521 /** 522 * Create a Aware network interface. This only creates the Linux interface - it doesn't actually 523 * create the data connection. 524 * 525 * @param transactionId Transaction ID for the transaction - used in the async callback to 526 * match with the original request. 527 * @param interfaceName The name of the interface, e.g. "aware0". 528 */ 529 public boolean createAwareNetworkInterface(short transactionId, String interfaceName) { 530 if (VDBG) { 531 Log.v(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", " 532 + "interfaceName=" + interfaceName); 533 } 534 535 IWifiNanIface iface = mHal.getWifiNanIface(); 536 if (iface == null) { 537 Log.e(TAG, "createAwareNetworkInterface: null interface"); 538 return false; 539 } 540 541 try { 542 WifiStatus status = iface.createDataInterfaceRequest(transactionId, interfaceName); 543 if (status.code == WifiStatusCode.SUCCESS) { 544 return true; 545 } else { 546 Log.e(TAG, "createAwareNetworkInterface: error: " + statusString(status)); 547 return false; 548 } 549 } catch (RemoteException e) { 550 Log.e(TAG, "createAwareNetworkInterface: exception: " + e); 551 return false; 552 } 553 } 554 555 /** 556 * Deletes a Aware network interface. The data connection can (should?) be torn down previously. 557 * 558 * @param transactionId Transaction ID for the transaction - used in the async callback to 559 * match with the original request. 560 * @param interfaceName The name of the interface, e.g. "aware0". 561 */ 562 public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) { 563 if (VDBG) { 564 Log.v(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", " 565 + "interfaceName=" + interfaceName); 566 } 567 568 IWifiNanIface iface = mHal.getWifiNanIface(); 569 if (iface == null) { 570 Log.e(TAG, "deleteAwareNetworkInterface: null interface"); 571 return false; 572 } 573 574 try { 575 WifiStatus status = iface.deleteDataInterfaceRequest(transactionId, interfaceName); 576 if (status.code == WifiStatusCode.SUCCESS) { 577 return true; 578 } else { 579 Log.e(TAG, "deleteAwareNetworkInterface: error: " + statusString(status)); 580 return false; 581 } 582 } catch (RemoteException e) { 583 Log.e(TAG, "deleteAwareNetworkInterface: exception: " + e); 584 return false; 585 } 586 } 587 588 /** 589 * Initiates setting up a data-path between device and peer. Security is provided by either 590 * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up. 591 * 592 * @param transactionId Transaction ID for the transaction - used in the async callback to 593 * match with the original request. 594 * @param peerId ID of the peer ID to associate the data path with. A value of 0 595 * indicates that not associated with an existing session. 596 * @param channelRequestType Indicates whether the specified channel is available, if available 597 * requested or forced (resulting in failure if cannot be 598 * accommodated). 599 * @param channel The channel on which to set up the data-path. 600 * @param peer The MAC address of the peer to create a connection with. 601 * @param interfaceName The interface on which to create the data connection. 602 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 603 * @param passphrase Passphrase for the data-path. 604 * @param capabilities The capabilities of the firmware. 605 */ 606 public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType, 607 int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase, 608 Capabilities capabilities) { 609 if (VDBG) { 610 Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId 611 + ", channelRequestType=" + channelRequestType + ", channel=" + channel 612 + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName=" 613 + interfaceName); 614 } 615 616 IWifiNanIface iface = mHal.getWifiNanIface(); 617 if (iface == null) { 618 Log.e(TAG, "initiateDataPath: null interface"); 619 return false; 620 } 621 622 if (capabilities == null) { 623 Log.e(TAG, "initiateDataPath: null capabilities"); 624 return false; 625 } 626 627 NanInitiateDataPathRequest req = new NanInitiateDataPathRequest(); 628 req.peerId = peerId; 629 copyArray(peer, req.peerDiscMacAddr); 630 req.channelRequestType = channelRequestType; 631 req.channel = channel; 632 req.ifaceName = interfaceName; 633 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 634 if (pmk != null && pmk.length != 0) { 635 req.securityConfig.cipherType = getStrongestCipherSuiteType( 636 capabilities.supportedCipherSuites); 637 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 638 copyArray(pmk, req.securityConfig.pmk); 639 } 640 if (passphrase != null && passphrase.length() != 0) { 641 req.securityConfig.cipherType = getStrongestCipherSuiteType( 642 capabilities.supportedCipherSuites); 643 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 644 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 645 } 646 647 try { 648 WifiStatus status = iface.initiateDataPathRequest(transactionId, req); 649 if (status.code == WifiStatusCode.SUCCESS) { 650 return true; 651 } else { 652 Log.e(TAG, "initiateDataPath: error: " + statusString(status)); 653 return false; 654 } 655 } catch (RemoteException e) { 656 Log.e(TAG, "initiateDataPath: exception: " + e); 657 return false; 658 } 659 } 660 661 /** 662 * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not 663 * both) - if both are null then an open (unencrypted) link is set up. 664 * 665 * @param transactionId Transaction ID for the transaction - used in the async callback to 666 * match with the original request. 667 * @param accept Accept (true) or reject (false) the original call. 668 * @param ndpId The NDP (Aware data path) ID. Obtained from the request callback. 669 * @param interfaceName The interface on which the data path will be setup. Obtained from the 670 * request callback. 671 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 672 * @param passphrase Passphrase for the data-path. 673 * @param capabilities The capabilities of the firmware. 674 */ 675 public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId, 676 String interfaceName, byte[] pmk, String passphrase, Capabilities capabilities) { 677 if (VDBG) { 678 Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept=" 679 + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName); 680 } 681 682 IWifiNanIface iface = mHal.getWifiNanIface(); 683 if (iface == null) { 684 Log.e(TAG, "respondToDataPathRequest: null interface"); 685 return false; 686 } 687 688 if (capabilities == null) { 689 Log.e(TAG, "initiateDataPath: null capabilities"); 690 return false; 691 } 692 693 NanRespondToDataPathIndicationRequest req = new NanRespondToDataPathIndicationRequest(); 694 req.acceptRequest = accept; 695 req.ndpInstanceId = ndpId; 696 req.ifaceName = interfaceName; 697 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 698 if (pmk != null && pmk.length != 0) { 699 req.securityConfig.cipherType = getStrongestCipherSuiteType( 700 capabilities.supportedCipherSuites); 701 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 702 copyArray(pmk, req.securityConfig.pmk); 703 } 704 if (passphrase != null && passphrase.length() != 0) { 705 req.securityConfig.cipherType = getStrongestCipherSuiteType( 706 capabilities.supportedCipherSuites); 707 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 708 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 709 } 710 711 try { 712 WifiStatus status = iface.respondToDataPathIndicationRequest(transactionId, req); 713 if (status.code == WifiStatusCode.SUCCESS) { 714 return true; 715 } else { 716 Log.e(TAG, "respondToDataPathRequest: error: " + statusString(status)); 717 return false; 718 } 719 } catch (RemoteException e) { 720 Log.e(TAG, "respondToDataPathRequest: exception: " + e); 721 return false; 722 } 723 } 724 725 /** 726 * Terminate an existing data-path (does not delete the interface). 727 * 728 * @param transactionId Transaction ID for the transaction - used in the async callback to 729 * match with the original request. 730 * @param ndpId The NDP (Aware data path) ID to be terminated. 731 */ 732 public boolean endDataPath(short transactionId, int ndpId) { 733 if (VDBG) { 734 Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId); 735 } 736 737 IWifiNanIface iface = mHal.getWifiNanIface(); 738 if (iface == null) { 739 Log.e(TAG, "endDataPath: null interface"); 740 return false; 741 } 742 743 try { 744 WifiStatus status = iface.terminateDataPathRequest(transactionId, ndpId); 745 if (status.code == WifiStatusCode.SUCCESS) { 746 return true; 747 } else { 748 Log.e(TAG, "endDataPath: error: " + statusString(status)); 749 return false; 750 } 751 } catch (RemoteException e) { 752 Log.e(TAG, "endDataPath: exception: " + e); 753 return false; 754 } 755 } 756 757 758 // utilities 759 760 /** 761 * Returns the strongest supported cipher suite. 762 * 763 * Baseline is very simple: 256 > 128 > 0. 764 */ 765 private int getStrongestCipherSuiteType(int supportedCipherSuites) { 766 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_256_MASK) != 0) { 767 return NanCipherSuiteType.SHARED_KEY_256_MASK; 768 } 769 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_128_MASK) != 0) { 770 return NanCipherSuiteType.SHARED_KEY_128_MASK; 771 } 772 return NanCipherSuiteType.NONE; 773 } 774 775 /** 776 * Converts a byte[] to an ArrayList<Byte>. Fills in the entries of the 'to' array if 777 * provided (non-null), otherwise creates and returns a new ArrayList<>. 778 * 779 * @param from The input byte[] to convert from. 780 * @param to An optional ArrayList<> to fill in from 'from'. 781 * 782 * @return A newly allocated ArrayList<> if 'to' is null, otherwise null. 783 */ 784 private ArrayList<Byte> convertNativeByteArrayToArrayList(byte[] from, ArrayList<Byte> to) { 785 if (from == null) { 786 from = new byte[0]; 787 } 788 789 if (to == null) { 790 to = new ArrayList<>(from.length); 791 } else { 792 to.ensureCapacity(from.length); 793 } 794 for (int i = 0; i < from.length; ++i) { 795 to.add(from[i]); 796 } 797 return to; 798 } 799 800 private void copyArray(byte[] from, byte[] to) { 801 if (from == null || to == null || from.length != to.length) { 802 Log.e(TAG, "copyArray error: from=" + from + ", to=" + to); 803 return; 804 } 805 for (int i = 0; i < from.length; ++i) { 806 to[i] = from[i]; 807 } 808 } 809 810 private static String statusString(WifiStatus status) { 811 if (status == null) { 812 return "status=null"; 813 } 814 StringBuilder sb = new StringBuilder(); 815 sb.append(status.code).append(" (").append(status.description).append(")"); 816 return sb.toString(); 817 } 818 819 /** 820 * Dump the internal state of the class. 821 */ 822 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 823 mHal.dump(fd, pw, args); 824 } 825} 826