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