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