1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi.p2p; 18 19 import android.annotation.NonNull; 20 import android.hardware.wifi.supplicant.V1_0.ISupplicantP2pIfaceCallback; 21 import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 22 import android.net.wifi.WpsInfo; 23 import android.net.wifi.p2p.WifiP2pConfig; 24 import android.net.wifi.p2p.WifiP2pDevice; 25 import android.net.wifi.p2p.WifiP2pGroup; 26 import android.net.wifi.p2p.WifiP2pProvDiscEvent; 27 import android.net.wifi.p2p.WifiP2pWfdInfo; 28 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 29 import android.util.Log; 30 31 import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus; 32 import com.android.server.wifi.util.NativeUtil; 33 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.List; 37 38 /** 39 * Class used for processing all P2P callbacks. 40 */ 41 public class SupplicantP2pIfaceCallbackImpl extends ISupplicantP2pIfaceCallback.Stub { 42 private static final String TAG = "SupplicantP2pIfaceCallbackImpl"; 43 private static boolean sVerboseLoggingEnabled = true; 44 45 private final SupplicantP2pIfaceHal mP2pIfaceHal; 46 private final String mInterface; 47 private final WifiP2pMonitor mMonitor; 48 SupplicantP2pIfaceCallbackImpl( @onNull SupplicantP2pIfaceHal p2pIfaceHal, @NonNull String iface, @NonNull WifiP2pMonitor monitor)49 public SupplicantP2pIfaceCallbackImpl( 50 @NonNull SupplicantP2pIfaceHal p2pIfaceHal, 51 @NonNull String iface, @NonNull WifiP2pMonitor monitor) { 52 mP2pIfaceHal = p2pIfaceHal; 53 mInterface = iface; 54 mMonitor = monitor; 55 } 56 57 /** 58 * Enable verbose logging for all sub modules. 59 */ enableVerboseLogging(int verbose)60 public static void enableVerboseLogging(int verbose) { 61 sVerboseLoggingEnabled = verbose > 0; 62 } 63 logd(String s)64 protected static void logd(String s) { 65 if (sVerboseLoggingEnabled) Log.d(TAG, s); 66 } 67 68 /** 69 * Used to indicate that a new network has been added. 70 * 71 * @param networkId Network ID allocated to the corresponding network. 72 */ onNetworkAdded(int networkId)73 public void onNetworkAdded(int networkId) { 74 } 75 76 77 /** 78 * Used to indicate that a network has been removed. 79 * 80 * @param networkId Network ID allocated to the corresponding network. 81 */ onNetworkRemoved(int networkId)82 public void onNetworkRemoved(int networkId) { 83 } 84 85 86 /** 87 * Used to indicate that a P2P device has been found. 88 * 89 * @param srcAddress MAC address of the device found. This must either 90 * be the P2P device address or the P2P interface address. 91 * @param p2pDeviceAddress P2P device address. 92 * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P 93 * Technical specification v1.2. 94 * @param deviceName Name of the device. 95 * @param configMethods Mask of WPS configuration methods supported by the 96 * device. 97 * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical 98 * specification v1.2. 99 * @param groupCapabilities Refer to section 4.1.4 of Wifi P2P Technical 100 * specification v1.2. 101 * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD 102 * technical specification v1.0.0. 103 */ onDeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, short configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo)104 public void onDeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, 105 String deviceName, short configMethods, byte deviceCapabilities, int groupCapabilities, 106 byte[] wfdDeviceInfo) { 107 WifiP2pDevice device = new WifiP2pDevice(); 108 device.deviceName = deviceName; 109 if (deviceName == null) { 110 Log.e(TAG, "Missing device name."); 111 return; 112 } 113 114 try { 115 device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); 116 } catch (Exception e) { 117 Log.e(TAG, "Could not decode device address.", e); 118 return; 119 } 120 121 try { 122 device.primaryDeviceType = NativeUtil.wpsDevTypeStringFromByteArray(primaryDeviceType); 123 } catch (Exception e) { 124 Log.e(TAG, "Could not encode device primary type.", e); 125 return; 126 } 127 128 device.deviceCapability = deviceCapabilities; 129 device.groupCapability = groupCapabilities; 130 device.wpsConfigMethodsSupported = configMethods; 131 device.status = WifiP2pDevice.AVAILABLE; 132 133 if (wfdDeviceInfo != null && wfdDeviceInfo.length >= 6) { 134 device.wfdInfo = new WifiP2pWfdInfo( 135 ((wfdDeviceInfo[0] & 0xFF) << 8) + (wfdDeviceInfo[1] & 0xFF), 136 ((wfdDeviceInfo[2] & 0xFF) << 8) + (wfdDeviceInfo[3] & 0xFF), 137 ((wfdDeviceInfo[4] & 0xFF) << 8) + (wfdDeviceInfo[5] & 0xFF)); 138 } 139 140 logd("Device discovered on " + mInterface + ": " + device); 141 mMonitor.broadcastP2pDeviceFound(mInterface, device); 142 } 143 144 /** 145 * Used to indicate that a P2P device has been lost. 146 * 147 * @param p2pDeviceAddress P2P device address. 148 */ onDeviceLost(byte[] p2pDeviceAddress)149 public void onDeviceLost(byte[] p2pDeviceAddress) { 150 WifiP2pDevice device = new WifiP2pDevice(); 151 152 try { 153 device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); 154 } catch (Exception e) { 155 Log.e(TAG, "Could not decode device address.", e); 156 return; 157 } 158 159 device.status = WifiP2pDevice.UNAVAILABLE; 160 161 logd("Device lost on " + mInterface + ": " + device); 162 mMonitor.broadcastP2pDeviceLost(mInterface, device); 163 } 164 165 166 /** 167 * Used to indicate the termination of P2P find operation. 168 */ onFindStopped()169 public void onFindStopped() { 170 logd("Search stopped on " + mInterface); 171 mMonitor.broadcastP2pFindStopped(mInterface); 172 } 173 174 175 /** 176 * Used to indicate the reception of a P2P Group Owner negotiation request. 177 * 178 * @param srcAddress MAC address of the device that initiated the GO 179 * negotiation request. 180 * @param passwordId Type of password. 181 */ onGoNegotiationRequest(byte[] srcAddress, short passwordId)182 public void onGoNegotiationRequest(byte[] srcAddress, short passwordId) { 183 WifiP2pConfig config = new WifiP2pConfig(); 184 185 try { 186 config.deviceAddress = NativeUtil.macAddressFromByteArray(srcAddress); 187 } catch (Exception e) { 188 Log.e(TAG, "Could not decode device address.", e); 189 return; 190 } 191 192 config.wps = new WpsInfo(); 193 194 switch (passwordId) { 195 case WpsDevPasswordId.USER_SPECIFIED: 196 config.wps.setup = WpsInfo.DISPLAY; 197 break; 198 199 case WpsDevPasswordId.PUSHBUTTON: 200 config.wps.setup = WpsInfo.PBC; 201 break; 202 203 case WpsDevPasswordId.REGISTRAR_SPECIFIED: 204 config.wps.setup = WpsInfo.KEYPAD; 205 break; 206 207 default: 208 config.wps.setup = WpsInfo.PBC; 209 break; 210 } 211 212 logd("Group Owner negotiation initiated on " + mInterface + ": " + config); 213 mMonitor.broadcastP2pGoNegotiationRequest(mInterface, config); 214 } 215 216 217 /** 218 * Used to indicate the completion of a P2P Group Owner negotiation request. 219 * 220 * @param status Status of the GO negotiation. 221 */ onGoNegotiationCompleted(int status)222 public void onGoNegotiationCompleted(int status) { 223 logd("Group Owner negotiation completed with status: " + status); 224 P2pStatus result = halStatusToP2pStatus(status); 225 226 if (result == P2pStatus.SUCCESS) { 227 mMonitor.broadcastP2pGoNegotiationSuccess(mInterface); 228 } else { 229 mMonitor.broadcastP2pGoNegotiationFailure(mInterface, result); 230 } 231 } 232 233 234 /** 235 * Used to indicate a successful formation of a P2P group. 236 */ onGroupFormationSuccess()237 public void onGroupFormationSuccess() { 238 logd("Group formation successful on " + mInterface); 239 mMonitor.broadcastP2pGroupFormationSuccess(mInterface); 240 } 241 242 243 /** 244 * Used to indicate a failure to form a P2P group. 245 * 246 * @param failureReason Failure reason string for debug purposes. 247 */ onGroupFormationFailure(String failureReason)248 public void onGroupFormationFailure(String failureReason) { 249 // TODO(ender): failureReason should probably be an int (P2pStatusCode). 250 logd("Group formation failed on " + mInterface + ": " + failureReason); 251 mMonitor.broadcastP2pGroupFormationFailure(mInterface, failureReason); 252 } 253 254 255 /** 256 * Used to indicate the start of a P2P group. 257 * 258 * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1) 259 * @param isGo Whether this device is owner of the group. 260 * @param ssid SSID of the group. 261 * @param frequency Frequency on which this group is created. 262 * @param psk PSK used to secure the group. 263 * @param passphrase PSK passphrase used to secure the group. 264 * @param goDeviceAddress MAC Address of the owner of this group. 265 * @param isPersistent Whether this group is persisted or not. 266 */ onGroupStarted(String groupIfName, boolean isGo, ArrayList<Byte> ssid, int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, boolean isPersistent)267 public void onGroupStarted(String groupIfName, boolean isGo, ArrayList<Byte> ssid, 268 int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, 269 boolean isPersistent) { 270 if (groupIfName == null) { 271 Log.e(TAG, "Missing group interface name."); 272 return; 273 } 274 275 logd("Group " + groupIfName + " started on " + mInterface); 276 277 WifiP2pGroup group = new WifiP2pGroup(); 278 group.setInterface(groupIfName); 279 280 try { 281 String quotedSsid = NativeUtil.encodeSsid(ssid); 282 group.setNetworkName(NativeUtil.removeEnclosingQuotes(quotedSsid)); 283 } catch (Exception e) { 284 Log.e(TAG, "Could not encode SSID.", e); 285 return; 286 } 287 288 group.setFrequency(frequency); 289 group.setIsGroupOwner(isGo); 290 group.setPassphrase(passphrase); 291 292 if (isPersistent) { 293 group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); 294 } else { 295 group.setNetworkId(WifiP2pGroup.NETWORK_ID_TEMPORARY); 296 } 297 298 WifiP2pDevice owner = new WifiP2pDevice(); 299 300 try { 301 owner.deviceAddress = NativeUtil.macAddressFromByteArray(goDeviceAddress); 302 } catch (Exception e) { 303 Log.e(TAG, "Could not decode Group Owner address.", e); 304 return; 305 } 306 307 group.setOwner(owner); 308 mMonitor.broadcastP2pGroupStarted(mInterface, group); 309 } 310 311 312 /** 313 * Used to indicate the removal of a P2P group. 314 * 315 * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1) 316 * @param isGo Whether this device is owner of the group. 317 */ onGroupRemoved(String groupIfName, boolean isGo)318 public void onGroupRemoved(String groupIfName, boolean isGo) { 319 if (groupIfName == null) { 320 Log.e(TAG, "Missing group name."); 321 return; 322 } 323 324 logd("Group " + groupIfName + " removed from " + mInterface); 325 WifiP2pGroup group = new WifiP2pGroup(); 326 group.setInterface(groupIfName); 327 group.setIsGroupOwner(isGo); 328 mMonitor.broadcastP2pGroupRemoved(mInterface, group); 329 } 330 331 332 /** 333 * Used to indicate the reception of a P2P invitation. 334 * 335 * @param srcAddress MAC address of the device that sent the invitation. 336 * @param goDeviceAddress MAC Address of the owner of this group. 337 * @param bssid Bssid of the group. 338 * @param persistentNetworkId Persistent network Id of the group. 339 * @param operatingFrequency Frequency on which the invitation was received. 340 */ onInvitationReceived(byte[] srcAddress, byte[] goDeviceAddress, byte[] bssid, int persistentNetworkId, int operatingFrequency)341 public void onInvitationReceived(byte[] srcAddress, byte[] goDeviceAddress, 342 byte[] bssid, int persistentNetworkId, int operatingFrequency) { 343 WifiP2pGroup group = new WifiP2pGroup(); 344 group.setNetworkId(persistentNetworkId); 345 346 WifiP2pDevice client = new WifiP2pDevice(); 347 348 try { 349 client.deviceAddress = NativeUtil.macAddressFromByteArray(srcAddress); 350 } catch (Exception e) { 351 Log.e(TAG, "Could not decode MAC address.", e); 352 return; 353 } 354 355 group.addClient(client); 356 357 WifiP2pDevice owner = new WifiP2pDevice(); 358 359 try { 360 owner.deviceAddress = NativeUtil.macAddressFromByteArray(goDeviceAddress); 361 } catch (Exception e) { 362 Log.e(TAG, "Could not decode Group Owner MAC address.", e); 363 return; 364 } 365 366 group.setOwner(owner); 367 368 logd("Invitation received on " + mInterface + ": " + group); 369 mMonitor.broadcastP2pInvitationReceived(mInterface, group); 370 } 371 372 373 /** 374 * Used to indicate the result of the P2P invitation request. 375 * 376 * @param bssid Bssid of the group. 377 * @param status Status of the invitation. 378 */ onInvitationResult(byte[] bssid, int status)379 public void onInvitationResult(byte[] bssid, int status) { 380 logd("Invitation completed with status: " + status); 381 mMonitor.broadcastP2pInvitationResult(mInterface, halStatusToP2pStatus(status)); 382 } 383 384 385 /** 386 * Used to indicate the completion of a P2P provision discovery request. 387 * 388 * @param p2pDeviceAddress P2P device address. 389 * @param isRequest Whether we received or sent the provision discovery. 390 * @param status Status of the provision discovery (SupplicantStatusCode). 391 * @param configMethods Mask of WPS configuration methods supported. 392 * Only one configMethod bit should be set per call. 393 * @param generatedPin 8 digit pin generated. 394 */ onProvisionDiscoveryCompleted(byte[] p2pDeviceAddress, boolean isRequest, byte status, short configMethods, String generatedPin)395 public void onProvisionDiscoveryCompleted(byte[] p2pDeviceAddress, boolean isRequest, 396 byte status, short configMethods, String generatedPin) { 397 if (status != ISupplicantP2pIfaceCallback.P2pProvDiscStatusCode.SUCCESS) { 398 Log.e(TAG, "Provision discovery failed: " + status); 399 mMonitor.broadcastP2pProvisionDiscoveryFailure(mInterface); 400 return; 401 } 402 403 logd("Provision discovery " + (isRequest ? "request" : "response") 404 + " for WPS Config method: " + configMethods); 405 406 WifiP2pProvDiscEvent event = new WifiP2pProvDiscEvent(); 407 event.device = new WifiP2pDevice(); 408 409 try { 410 event.device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); 411 } catch (Exception e) { 412 Log.e(TAG, "Could not decode MAC address.", e); 413 return; 414 } 415 416 if ((configMethods & WpsConfigMethods.PUSHBUTTON) != 0) { 417 if (isRequest) { 418 event.event = WifiP2pProvDiscEvent.PBC_REQ; 419 mMonitor.broadcastP2pProvisionDiscoveryPbcRequest(mInterface, event); 420 } else { 421 event.event = WifiP2pProvDiscEvent.PBC_RSP; 422 mMonitor.broadcastP2pProvisionDiscoveryPbcResponse(mInterface, event); 423 } 424 } else if (!isRequest && (configMethods & WpsConfigMethods.KEYPAD) != 0) { 425 event.event = WifiP2pProvDiscEvent.SHOW_PIN; 426 event.pin = generatedPin; 427 mMonitor.broadcastP2pProvisionDiscoveryShowPin(mInterface, event); 428 } else if (!isRequest && (configMethods & WpsConfigMethods.DISPLAY) != 0) { 429 event.event = WifiP2pProvDiscEvent.ENTER_PIN; 430 mMonitor.broadcastP2pProvisionDiscoveryEnterPin(mInterface, event); 431 } else if (isRequest && (configMethods & WpsConfigMethods.DISPLAY) != 0) { 432 event.event = WifiP2pProvDiscEvent.SHOW_PIN; 433 event.pin = generatedPin; 434 mMonitor.broadcastP2pProvisionDiscoveryShowPin(mInterface, event); 435 } else if (isRequest && (configMethods & WpsConfigMethods.KEYPAD) != 0) { 436 event.event = WifiP2pProvDiscEvent.ENTER_PIN; 437 mMonitor.broadcastP2pProvisionDiscoveryEnterPin(mInterface, event); 438 } else { 439 Log.e(TAG, "Unsupported config methods: " + configMethods); 440 } 441 } 442 443 444 /** 445 * Used to indicate the reception of a P2P service discovery response. 446 * 447 * @param srcAddress MAC address of the device that sent the service discovery. 448 * @param updateIndicator Service update indicator. Refer to section 3.1.3 of 449 * Wifi P2P Technical specification v1.2. 450 * @param tlvs Refer to section 3.1.3.1 of Wifi P2P Technical specification v1.2. 451 */ onServiceDiscoveryResponse(byte[] srcAddress, short updateIndicator, ArrayList<Byte> tlvs)452 public void onServiceDiscoveryResponse(byte[] srcAddress, short updateIndicator, 453 ArrayList<Byte> tlvs) { 454 List<WifiP2pServiceResponse> response = null; 455 456 logd("Service discovery response received on " + mInterface); 457 try { 458 String srcAddressStr = NativeUtil.macAddressFromByteArray(srcAddress); 459 // updateIndicator is not used 460 response = WifiP2pServiceResponse.newInstance(srcAddressStr, 461 NativeUtil.byteArrayFromArrayList(tlvs)); 462 } catch (Exception e) { 463 Log.e(TAG, "Could not process service discovery response.", e); 464 return; 465 } 466 mMonitor.broadcastP2pServiceDiscoveryResponse(mInterface, response); 467 } 468 createStaEventDevice(byte[] srcAddress, byte[] p2pDeviceAddress)469 private WifiP2pDevice createStaEventDevice(byte[] srcAddress, byte[] p2pDeviceAddress) { 470 WifiP2pDevice device = new WifiP2pDevice(); 471 byte[] deviceAddressBytes; 472 // Legacy STAs may not supply a p2pDeviceAddress (signaled by a zero'd p2pDeviceAddress) 473 // In this case, use srcAddress instead 474 if (!Arrays.equals(NativeUtil.ANY_MAC_BYTES, p2pDeviceAddress)) { 475 deviceAddressBytes = p2pDeviceAddress; 476 } else { 477 deviceAddressBytes = srcAddress; 478 } 479 try { 480 device.deviceAddress = NativeUtil.macAddressFromByteArray(deviceAddressBytes); 481 } catch (Exception e) { 482 Log.e(TAG, "Could not decode MAC address", e); 483 return null; 484 } 485 return device; 486 } 487 488 /** 489 * Used to indicate when a STA device is connected to this device. 490 * 491 * @param srcAddress MAC address of the device that was authorized. 492 * @param p2pDeviceAddress P2P device address. 493 */ onStaAuthorized(byte[] srcAddress, byte[] p2pDeviceAddress)494 public void onStaAuthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { 495 logd("STA authorized on " + mInterface); 496 WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress); 497 if (device == null) { 498 return; 499 } 500 mMonitor.broadcastP2pApStaConnected(mInterface, device); 501 } 502 503 504 /** 505 * Used to indicate when a STA device is disconnected from this device. 506 * 507 * @param srcAddress MAC address of the device that was deauthorized. 508 * @param p2pDeviceAddress P2P device address. 509 */ onStaDeauthorized(byte[] srcAddress, byte[] p2pDeviceAddress)510 public void onStaDeauthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { 511 logd("STA deauthorized on " + mInterface); 512 WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress); 513 if (device == null) { 514 return; 515 } 516 mMonitor.broadcastP2pApStaDisconnected(mInterface, device); 517 } 518 519 halStatusToP2pStatus(int status)520 private static P2pStatus halStatusToP2pStatus(int status) { 521 P2pStatus result = P2pStatus.UNKNOWN; 522 523 switch (status) { 524 case P2pStatusCode.SUCCESS: 525 case P2pStatusCode.SUCCESS_DEFERRED: 526 result = P2pStatus.SUCCESS; 527 break; 528 529 case P2pStatusCode.FAIL_INFO_CURRENTLY_UNAVAILABLE: 530 result = P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE; 531 break; 532 533 case P2pStatusCode.FAIL_INCOMPATIBLE_PARAMS: 534 result = P2pStatus.INCOMPATIBLE_PARAMETERS; 535 break; 536 537 case P2pStatusCode.FAIL_LIMIT_REACHED: 538 result = P2pStatus.LIMIT_REACHED; 539 break; 540 541 case P2pStatusCode.FAIL_INVALID_PARAMS: 542 result = P2pStatus.INVALID_PARAMETER; 543 break; 544 545 case P2pStatusCode.FAIL_UNABLE_TO_ACCOMMODATE: 546 result = P2pStatus.UNABLE_TO_ACCOMMODATE_REQUEST; 547 break; 548 549 case P2pStatusCode.FAIL_PREV_PROTOCOL_ERROR: 550 result = P2pStatus.PREVIOUS_PROTOCOL_ERROR; 551 break; 552 553 case P2pStatusCode.FAIL_NO_COMMON_CHANNELS: 554 result = P2pStatus.NO_COMMON_CHANNEL; 555 break; 556 557 case P2pStatusCode.FAIL_UNKNOWN_GROUP: 558 result = P2pStatus.UNKNOWN_P2P_GROUP; 559 break; 560 561 case P2pStatusCode.FAIL_BOTH_GO_INTENT_15: 562 result = P2pStatus.BOTH_GO_INTENT_15; 563 break; 564 565 case P2pStatusCode.FAIL_INCOMPATIBLE_PROV_METHOD: 566 result = P2pStatus.INCOMPATIBLE_PROVISIONING_METHOD; 567 break; 568 569 case P2pStatusCode.FAIL_REJECTED_BY_USER: 570 result = P2pStatus.REJECTED_BY_USER; 571 break; 572 } 573 return result; 574 } 575 } 576 577