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