/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi.p2p; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTL; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback; import android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo; import android.hardware.wifi.supplicant.P2pDeviceFoundEventParams; import android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams; import android.hardware.wifi.supplicant.P2pGroupStartedEventParams; import android.hardware.wifi.supplicant.P2pInvitationEventParams; import android.hardware.wifi.supplicant.P2pPeerClientDisconnectedEventParams; import android.hardware.wifi.supplicant.P2pPeerClientJoinedEventParams; import android.hardware.wifi.supplicant.P2pProvDiscStatusCode; import android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParams; import android.hardware.wifi.supplicant.P2pStatusCode; import android.hardware.wifi.supplicant.WpsConfigMethods; import android.hardware.wifi.supplicant.WpsDevPasswordId; import android.net.MacAddress; import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pProvDiscEvent; import android.net.wifi.p2p.WifiP2pWfdInfo; import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; import android.text.TextUtils; import android.util.Log; import com.android.internal.util.HexDump; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import java.io.ByteArrayInputStream; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Class used for processing all P2P callbacks for the AIDL implementation. */ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallback.Stub { private static final String TAG = "SupplicantP2pIfaceCallbackAidlImpl"; private static boolean sVerboseLoggingEnabled = true; private final String mInterface; private final WifiP2pMonitor mMonitor; private final int mServiceVersion; public SupplicantP2pIfaceCallbackAidlImpl( @NonNull String iface, @NonNull WifiP2pMonitor monitor, int serviceVersion) { mInterface = iface; mMonitor = monitor; mServiceVersion = serviceVersion; } /** * Enable verbose logging for all sub modules. */ public static void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { sVerboseLoggingEnabled = verboseEnabled; } protected static void logd(String msg) { if (sVerboseLoggingEnabled) { Log.d(TAG, msg, null); } } /** * Used to indicate that a P2P device has been found. * * @param srcAddress MAC address of the device found. This must either * be the P2P device address or the P2P interface address. * @param p2pDeviceAddress P2P device address. * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P * Technical specification v1.2. * @param deviceName Name of the device. * @param configMethods Mask of WPS configuration methods supported by the * device. * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param groupCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD * technical specification v1.0.0. */ @Override public void onDeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, int configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo) { handleDeviceFound(srcAddress, p2pDeviceAddress, primaryDeviceType, deviceName, configMethods, deviceCapabilities, groupCapabilities, wfdDeviceInfo, null, null, null); } /** * Used to indicate that a P2P device has been lost. * * @param p2pDeviceAddress P2P device address. */ @Override public void onDeviceLost(byte[] p2pDeviceAddress) { WifiP2pDevice device = new WifiP2pDevice(); try { device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode device address.", e); return; } device.status = WifiP2pDevice.UNAVAILABLE; logd("Device lost on " + mInterface + ": " + device); mMonitor.broadcastP2pDeviceLost(mInterface, device); } /** * Used to indicate the termination of P2P find operation. */ @Override public void onFindStopped() { logd("Search stopped on " + mInterface); mMonitor.broadcastP2pFindStopped(mInterface); } /** * Used to indicate the reception of a P2P Group Owner negotiation request. * * @param srcAddress MAC address of the device that initiated the GO * negotiation request. * @param passwordId Type of password. */ @Override public void onGoNegotiationRequest(byte[] srcAddress, int passwordId) { handleGoNegotiationRequestEvent(srcAddress, passwordId, null); } /** * Used to indicate the reception of a P2P Group Owner negotiation request. * * @param goNegotiationReqEventParams Parameters associated with * GO negotiation request. */ @Override public void onGoNegotiationRequestWithParams( P2pGoNegotiationReqEventParams goNegotiationReqEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && goNegotiationReqEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( goNegotiationReqEventParams.vendorData); } handleGoNegotiationRequestEvent( goNegotiationReqEventParams.srcAddress, goNegotiationReqEventParams.passwordId, vendorData); } private void handleGoNegotiationRequestEvent( byte[] srcAddress, int passwordId, @Nullable List<OuiKeyedData> vendorData) { WifiP2pConfig config = new WifiP2pConfig(); try { config.deviceAddress = NativeUtil.macAddressFromByteArray(srcAddress); } catch (Exception e) { Log.e(TAG, "Could not decode device address.", e); return; } if (SdkLevel.isAtLeastV() && vendorData != null) { config.setVendorData(vendorData); } config.wps = new WpsInfo(); switch (passwordId) { case WpsDevPasswordId.USER_SPECIFIED: config.wps.setup = WpsInfo.DISPLAY; break; case WpsDevPasswordId.PUSHBUTTON: config.wps.setup = WpsInfo.PBC; break; case WpsDevPasswordId.REGISTRAR_SPECIFIED: config.wps.setup = WpsInfo.KEYPAD; break; default: config.wps.setup = WpsInfo.PBC; break; } logd("Group Owner negotiation initiated on " + mInterface + ": " + config); mMonitor.broadcastP2pGoNegotiationRequest(mInterface, config); } /** * Used to indicate the completion of a P2P Group Owner negotiation request. * * @param status Status of the GO negotiation. */ @Override public void onGoNegotiationCompleted(int status) { logd("Group Owner negotiation completed with status: " + status); WifiP2pServiceImpl.P2pStatus result = halStatusToP2pStatus(status); if (result == WifiP2pServiceImpl.P2pStatus.SUCCESS) { mMonitor.broadcastP2pGoNegotiationSuccess(mInterface); } else { mMonitor.broadcastP2pGoNegotiationFailure(mInterface, result); } } /** * Used to indicate a successful formation of a P2P group. */ @Override public void onGroupFormationSuccess() { logd("Group formation successful on " + mInterface); mMonitor.broadcastP2pGroupFormationSuccess(mInterface); } /** * Used to indicate a failure to form a P2P group. * * @param failureReason Failure reason string for debug purposes. */ @Override public void onGroupFormationFailure(String failureReason) { logd("Group formation failed on " + mInterface + ": " + failureReason); mMonitor.broadcastP2pGroupFormationFailure(mInterface, failureReason); } /** * Used to indicate the start of a P2P group. * * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1) * @param isGroupOwner Whether this device is owner of the group. * @param ssid SSID of the group. * @param frequency Frequency on which this group is created. * @param psk PSK used to secure the group. * @param passphrase PSK passphrase used to secure the group. * @param goDeviceAddress MAC Address of the owner of this group. * @param isPersistent Whether this group is persisted or not. */ @Override public void onGroupStarted(String groupIfName, boolean isGroupOwner, byte[] ssid, int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, boolean isPersistent) { onGroupStarted(groupIfName, isGroupOwner, ssid, frequency, psk, passphrase, goDeviceAddress, isPersistent, /* goInterfaceAddress */ null, /*p2pClientIpInfo */ null, /* vendorData */ null); } /** * Used to indicate the start of a P2P group, with some parameters describing the group. * * @param groupStartedEventParams Parameters describing the P2P group. */ @Override public void onGroupStartedWithParams(P2pGroupStartedEventParams groupStartedEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && groupStartedEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( groupStartedEventParams.vendorData); } onGroupStarted(groupStartedEventParams.groupInterfaceName, groupStartedEventParams.isGroupOwner, groupStartedEventParams.ssid, groupStartedEventParams.frequencyMHz, groupStartedEventParams.psk, groupStartedEventParams.passphrase, groupStartedEventParams.goDeviceAddress, groupStartedEventParams.isPersistent, groupStartedEventParams.goInterfaceAddress, groupStartedEventParams.isP2pClientEapolIpAddressInfoPresent ? groupStartedEventParams.p2pClientIpInfo : null, vendorData); } private void onGroupStarted(String groupIfName, boolean isGroupOwner, byte[] ssid, int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, boolean isPersistent, byte[] goInterfaceAddress, P2pClientEapolIpAddressInfo p2pClientIpInfo, @Nullable List<OuiKeyedData> vendorData) { if (groupIfName == null) { Log.e(TAG, "Missing group interface name."); return; } logd("Group " + groupIfName + " started on " + mInterface); WifiP2pGroup group = new WifiP2pGroup(); group.setInterface(groupIfName); try { String quotedSsid = NativeUtil.encodeSsid( NativeUtil.byteArrayToArrayList(ssid)); group.setNetworkName(NativeUtil.removeEnclosingQuotes(quotedSsid)); } catch (Exception e) { Log.e(TAG, "Could not encode SSID.", e); return; } group.setFrequency(frequency); group.setIsGroupOwner(isGroupOwner); group.setPassphrase(passphrase); if (isPersistent) { group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); } else { group.setNetworkId(WifiP2pGroup.NETWORK_ID_TEMPORARY); } WifiP2pDevice owner = new WifiP2pDevice(); try { owner.deviceAddress = NativeUtil.macAddressFromByteArray(goDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode Group Owner address.", e); return; } group.interfaceAddress = goInterfaceAddress; group.setOwner(owner); if (!isGroupOwner && p2pClientIpInfo != null) { try { group.p2pClientEapolIpInfo = new WifiP2pGroup.P2pGroupClientEapolIpAddressData( intToInet4AddressHTL(p2pClientIpInfo.ipAddressClient), intToInet4AddressHTL(p2pClientIpInfo.ipAddressGo), intToInet4AddressHTL(p2pClientIpInfo.ipAddressMask)); } catch (Exception e) { Log.e(TAG, "Failed to fetch group client EAPOL IP address " + e); group.p2pClientEapolIpInfo = null; } } else { group.p2pClientEapolIpInfo = null; } if (SdkLevel.isAtLeastV() && vendorData != null) { group.setVendorData(vendorData); } mMonitor.broadcastP2pGroupStarted(mInterface, group); } /** * Used to indicate the removal of a P2P group. * * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1) * @param isGroupOwner Whether this device is owner of the group. */ @Override public void onGroupRemoved(String groupIfName, boolean isGroupOwner) { if (groupIfName == null) { Log.e(TAG, "Missing group name."); return; } logd("Group " + groupIfName + " removed from " + mInterface); WifiP2pGroup group = new WifiP2pGroup(); group.setInterface(groupIfName); group.setIsGroupOwner(isGroupOwner); mMonitor.broadcastP2pGroupRemoved(mInterface, group); } /** * Used to indicate the reception of a P2P invitation. * * @param srcAddress MAC address of the device that sent the invitation. * @param goDeviceAddress MAC Address of the owner of this group. * @param bssid Bssid of the group. * @param persistentNetworkId Persistent network Id of the group. * @param operatingFrequency Frequency on which the invitation was received. */ @Override public void onInvitationReceived(byte[] srcAddress, byte[] goDeviceAddress, byte[] bssid, int persistentNetworkId, int operatingFrequency) { handleInvitationReceivedEvent(srcAddress, goDeviceAddress, bssid, persistentNetworkId, operatingFrequency, null); } /** * Used to indicate the reception of a P2P invitation. * * @param invitationEventParams Parameters of the invitation event. */ @Override public void onInvitationReceivedWithParams( P2pInvitationEventParams invitationEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && invitationEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList(invitationEventParams.vendorData); } handleInvitationReceivedEvent( invitationEventParams.srcAddress, invitationEventParams.goDeviceAddress, invitationEventParams.bssid, invitationEventParams.persistentNetworkId, invitationEventParams.operatingFrequencyMHz, vendorData); } private void handleInvitationReceivedEvent( byte[] srcAddress, byte[] goDeviceAddress, byte[] bssid, int persistentNetworkId, int operatingFrequency, List<OuiKeyedData> vendorData) { WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(persistentNetworkId); WifiP2pDevice client = new WifiP2pDevice(); try { client.deviceAddress = NativeUtil.macAddressFromByteArray(srcAddress); } catch (Exception e) { Log.e(TAG, "Could not decode MAC address.", e); return; } group.addClient(client); WifiP2pDevice owner = new WifiP2pDevice(); try { owner.deviceAddress = NativeUtil.macAddressFromByteArray(goDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode Group Owner MAC address.", e); return; } group.setOwner(owner); if (SdkLevel.isAtLeastV() && vendorData != null) { group.setVendorData(vendorData); } logd("Invitation received on " + mInterface + ": " + group); mMonitor.broadcastP2pInvitationReceived(mInterface, group); } /** * Used to indicate the result of the P2P invitation request. * * @param bssid Bssid of the group. * @param status Status of the invitation. */ @Override public void onInvitationResult(byte[] bssid, int status) { logd("Invitation completed with status: " + status); mMonitor.broadcastP2pInvitationResult(mInterface, halStatusToP2pStatus(status)); } private @WifiP2pMonitor.P2pProvDiscStatus int convertHalProvDiscStatusToFrameworkStatus( int status) { switch (status) { case P2pProvDiscStatusCode.SUCCESS: return WifiP2pMonitor.PROV_DISC_STATUS_SUCCESS; case P2pProvDiscStatusCode.TIMEOUT: return WifiP2pMonitor.PROV_DISC_STATUS_TIMEOUT; case P2pProvDiscStatusCode.REJECTED: return WifiP2pMonitor.PROV_DISC_STATUS_REJECTED; case P2pProvDiscStatusCode.TIMEOUT_JOIN: return WifiP2pMonitor.PROV_DISC_STATUS_TIMEOUT_JOIN; case P2pProvDiscStatusCode.INFO_UNAVAILABLE: return WifiP2pMonitor.PROV_DISC_STATUS_INFO_UNAVAILABLE; default: return WifiP2pMonitor.PROV_DISC_STATUS_UNKNOWN; } } /** * Used to indicate the completion of a P2P provision discovery request. * * @param p2pDeviceAddress P2P device address. * @param isRequest Whether we received or sent the provision discovery. * @param status Status of the provision discovery (SupplicantStatusCode). * @param configMethods Mask of WPS configuration methods supported. * Only one configMethod bit should be set per call. * @param generatedPin 8 digit pin generated. */ @Override public void onProvisionDiscoveryCompleted(byte[] p2pDeviceAddress, boolean isRequest, byte status, int configMethods, String generatedPin) { handleProvisionDiscoveryCompletedEvent( p2pDeviceAddress, isRequest, status, configMethods, generatedPin, null, null); } /** * Used to indicate the completion of a P2P provision discovery request. * * @param provisionDiscoveryCompletedEventParams Parameters associated with P2P provision * discovery frame notification. */ @Override public void onProvisionDiscoveryCompletedEvent( P2pProvisionDiscoveryCompletedEventParams provisionDiscoveryCompletedEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && provisionDiscoveryCompletedEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( provisionDiscoveryCompletedEventParams.vendorData); } handleProvisionDiscoveryCompletedEvent( provisionDiscoveryCompletedEventParams.p2pDeviceAddress, provisionDiscoveryCompletedEventParams.isRequest, provisionDiscoveryCompletedEventParams.status, provisionDiscoveryCompletedEventParams.configMethods, provisionDiscoveryCompletedEventParams.generatedPin, provisionDiscoveryCompletedEventParams.groupInterfaceName, vendorData); } private void handleProvisionDiscoveryCompletedEvent( byte[] p2pDeviceAddress, boolean isRequest, byte status, int configMethods, String generatedPin, String groupIfName, @Nullable List<OuiKeyedData> vendorData) { logd( "Provision discovery " + (isRequest ? "request" : "response") + " for WPS Config method: " + configMethods + " status: " + status + " groupIfName: " + (TextUtils.isEmpty(groupIfName) ? "null" : groupIfName)); WifiP2pProvDiscEvent event = new WifiP2pProvDiscEvent(); event.device = new WifiP2pDevice(); try { event.device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode MAC address.", e); event.device.deviceAddress = null; } if (status != P2pProvDiscStatusCode.SUCCESS) { Log.e(TAG, "Provision discovery failed, status code: " + status); mMonitor.broadcastP2pProvisionDiscoveryFailure(mInterface, convertHalProvDiscStatusToFrameworkStatus(status), event); return; } if (TextUtils.isEmpty(event.device.deviceAddress)) return; if (SdkLevel.isAtLeastV() && vendorData != null) { event.setVendorData(vendorData); } if ((configMethods & WpsConfigMethods.PUSHBUTTON) != 0) { if (isRequest) { event.event = WifiP2pProvDiscEvent.PBC_REQ; mMonitor.broadcastP2pProvisionDiscoveryPbcRequest(mInterface, event); } else { event.event = WifiP2pProvDiscEvent.PBC_RSP; mMonitor.broadcastP2pProvisionDiscoveryPbcResponse(mInterface, event); } } else if (!isRequest && (configMethods & WpsConfigMethods.KEYPAD) != 0) { event.event = WifiP2pProvDiscEvent.SHOW_PIN; event.pin = generatedPin; mMonitor.broadcastP2pProvisionDiscoveryShowPin(mInterface, event); } else if (!isRequest && (configMethods & WpsConfigMethods.DISPLAY) != 0) { event.event = WifiP2pProvDiscEvent.ENTER_PIN; event.pin = generatedPin; mMonitor.broadcastP2pProvisionDiscoveryEnterPin(mInterface, event); } else if (isRequest && (configMethods & WpsConfigMethods.DISPLAY) != 0) { event.event = WifiP2pProvDiscEvent.SHOW_PIN; event.pin = generatedPin; mMonitor.broadcastP2pProvisionDiscoveryShowPin(mInterface, event); } else if (isRequest && (configMethods & WpsConfigMethods.KEYPAD) != 0) { event.event = WifiP2pProvDiscEvent.ENTER_PIN; mMonitor.broadcastP2pProvisionDiscoveryEnterPin(mInterface, event); } else { Log.e(TAG, "Unsupported config methods: " + configMethods); } } /** * Used to indicate the reception of a P2P service discovery response. * * @param srcAddress MAC address of the device that sent the service discovery. * @param updateIndicator Service update indicator. Refer to section 3.1.3 of * Wifi P2P Technical specification v1.2. * @param tlvs Refer to section 3.1.3.1 of Wifi P2P Technical specification v1.2. */ @Override public void onServiceDiscoveryResponse(byte[] srcAddress, char updateIndicator, byte[] tlvs) { List<WifiP2pServiceResponse> response = null; logd("Service discovery response received on " + mInterface); try { String srcAddressStr = NativeUtil.macAddressFromByteArray(srcAddress); // updateIndicator is not used response = WifiP2pServiceResponse.newInstance(srcAddressStr, tlvs); } catch (Exception e) { Log.e(TAG, "Could not process service discovery response.", e); return; } mMonitor.broadcastP2pServiceDiscoveryResponse(mInterface, response); } private WifiP2pDevice createStaEventDevice(byte[] interfaceAddress, byte[] p2pDeviceAddress, InetAddress ipAddress) { WifiP2pDevice device = new WifiP2pDevice(); byte[] deviceAddressBytes; // Legacy STAs may not supply a p2pDeviceAddress (signaled by a zero'd p2pDeviceAddress) // In this case, use interfaceAddress instead if (!Arrays.equals(NativeUtil.ANY_MAC_BYTES, p2pDeviceAddress)) { deviceAddressBytes = p2pDeviceAddress; } else { deviceAddressBytes = interfaceAddress; } try { device.deviceAddress = NativeUtil.macAddressFromByteArray(deviceAddressBytes); device.setInterfaceMacAddress(MacAddress.fromBytes(interfaceAddress)); } catch (Exception e) { Log.e(TAG, "Could not decode MAC address", e); return null; } device.setIpAddress(ipAddress); return device; } /** * Used to indicate when a STA device is connected to this device. * * @param srcAddress MAC address of the device that was authorized. * @param p2pDeviceAddress P2P device address. */ @Override public void onStaAuthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { onP2pApStaConnected(null, srcAddress, p2pDeviceAddress, 0, null); } /** * Used to indicate that a P2P client has joined this device group owner. * * @param clientJoinedEventParams Parameters associated with peer client joined event. */ @Override public void onPeerClientJoined(P2pPeerClientJoinedEventParams clientJoinedEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && clientJoinedEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( clientJoinedEventParams.vendorData); } onP2pApStaConnected( clientJoinedEventParams.groupInterfaceName, clientJoinedEventParams.clientInterfaceAddress, clientJoinedEventParams.clientDeviceAddress, clientJoinedEventParams.clientIpAddress, vendorData); } private void onP2pApStaConnected( String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress, int ipAddress, @Nullable List<OuiKeyedData> vendorData) { InetAddress ipAddressClient = null; logd("STA authorized on " + (TextUtils.isEmpty(groupIfName) ? mInterface : groupIfName)); if (ipAddress != 0) { ipAddressClient = intToInet4AddressHTL(ipAddress); logd("IP Address of Client: " + ipAddressClient.getHostAddress()); } WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress, ipAddressClient); if (device == null) { return; } if (SdkLevel.isAtLeastV() && vendorData != null) { device.setVendorData(vendorData); } mMonitor.broadcastP2pApStaConnected(mInterface, device); } /** * Used to indicate when a STA device is disconnected from this device. * * @param srcAddress MAC address of the device that was deauthorized. * @param p2pDeviceAddress P2P device address. */ @Override public void onStaDeauthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { onP2pApStaDisconnected(null, srcAddress, p2pDeviceAddress, null); } /** * Used to indicate that a P2P client has disconnected from this device group owner. * * @param clientDisconnectedEventParams Parameters associated with peer client disconnected * event. */ @Override public void onPeerClientDisconnected( P2pPeerClientDisconnectedEventParams clientDisconnectedEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && clientDisconnectedEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( clientDisconnectedEventParams.vendorData); } onP2pApStaDisconnected( clientDisconnectedEventParams.groupInterfaceName, clientDisconnectedEventParams.clientInterfaceAddress, clientDisconnectedEventParams.clientDeviceAddress, vendorData); } private void onP2pApStaDisconnected( String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress, @Nullable List<OuiKeyedData> vendorData) { logd("STA deauthorized on " + (TextUtils.isEmpty(groupIfName) ? mInterface : groupIfName)); WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress, null); if (device == null) { return; } if (SdkLevel.isAtLeastV() && vendorData != null) { device.setVendorData(vendorData); } mMonitor.broadcastP2pApStaDisconnected(mInterface, device); } /** * Used to indicate that a P2P WFD R2 device has been found. * * @param srcAddress MAC address of the device found. This must either * be the P2P device address or the P2P interface address. * @param p2pDeviceAddress P2P device address. * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P * Technical specification v1.2. * @param deviceName Name of the device. * @param configMethods Mask of WPS configuration methods supported by the * device. * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param groupCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD * technical specification v1.0.0. * @param wfdR2DeviceInfo WFD R2 device info as described in section 5.1.12 of WFD * technical specification v2.1. */ @Override public void onR2DeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, int configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo, byte[] wfdR2DeviceInfo) { WifiP2pDevice device = new WifiP2pDevice(); device.deviceName = deviceName; if (deviceName == null) { Log.e(TAG, "Missing device name."); return; } try { device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode device address.", e); return; } try { device.primaryDeviceType = NativeUtil.wpsDevTypeStringFromByteArray(primaryDeviceType); } catch (Exception e) { Log.e(TAG, "Could not encode device primary type.", e); return; } device.deviceCapability = deviceCapabilities; device.groupCapability = groupCapabilities; device.wpsConfigMethodsSupported = configMethods; device.status = WifiP2pDevice.AVAILABLE; if (wfdDeviceInfo != null && wfdDeviceInfo.length >= 6) { device.wfdInfo = new WifiP2pWfdInfo( ((wfdDeviceInfo[0] & 0xFF) << 8) + (wfdDeviceInfo[1] & 0xFF), ((wfdDeviceInfo[2] & 0xFF) << 8) + (wfdDeviceInfo[3] & 0xFF), ((wfdDeviceInfo[4] & 0xFF) << 8) + (wfdDeviceInfo[5] & 0xFF)); } if (wfdR2DeviceInfo != null && wfdR2DeviceInfo.length >= 2) { device.wfdInfo.setR2DeviceInfo( ((wfdR2DeviceInfo[0] & 0xFF) << 8) + (wfdR2DeviceInfo[1] & 0xFF)); } logd("R2 Device discovered on " + mInterface + ": " + device + " R2 Info:" + Arrays.toString(wfdR2DeviceInfo)); mMonitor.broadcastP2pDeviceFound(mInterface, device); } /** * Used to indicate the frequency changed notification. * * @param groupIfName Interface name of the group. * @param frequency New operating frequency. */ public void onGroupFrequencyChanged(String groupIfName, int frequency) { if (groupIfName == null) { Log.e(TAG, "Missing group interface name."); return; } logd("Frequency changed event on " + groupIfName + ". New frequency: " + frequency); mMonitor.broadcastP2pFrequencyChanged(mInterface, frequency); } /* * Used to indicate that a P2P device has been found. * * @param srcAddress MAC address of the device found. This must either * be the P2P device address or the P2P interface address. * @param p2pDeviceAddress P2P device address. * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P * Technical specification v1.2. * @param deviceName Name of the device. * @param configMethods Mask of WPS configuration methods supported by the * device. * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param groupCapabilities Refer to section 4.1.4 of Wifi P2P Technical * specification v1.2. * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD * technical specification v1.0.0. * @param wfdR2DeviceInfo WFD R2 device info as described in section 5.1.12 of WFD * technical specification v2.1. * @param vendorElemBytes bytes of vendor-specific information elements. */ @Override public void onDeviceFoundWithVendorElements(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, int configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo, byte[] wfdR2DeviceInfo, byte[] vendorElemBytes) { handleDeviceFound(srcAddress, p2pDeviceAddress, primaryDeviceType, deviceName, configMethods, deviceCapabilities, groupCapabilities, wfdDeviceInfo, wfdR2DeviceInfo, vendorElemBytes, null); } /** * Used to indicate that a P2P device has been found. * * @param deviceFoundEventParams Parameters associated with the device found event. */ @Override public void onDeviceFoundWithParams(P2pDeviceFoundEventParams deviceFoundEventParams) { List<OuiKeyedData> vendorData = null; if (mServiceVersion >= 3 && deviceFoundEventParams.vendorData != null) { vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( deviceFoundEventParams.vendorData); } handleDeviceFound( deviceFoundEventParams.srcAddress, deviceFoundEventParams.p2pDeviceAddress, deviceFoundEventParams.primaryDeviceType, deviceFoundEventParams.deviceName, deviceFoundEventParams.configMethods, deviceFoundEventParams.deviceCapabilities, deviceFoundEventParams.groupCapabilities, deviceFoundEventParams.wfdDeviceInfo, deviceFoundEventParams.wfdR2DeviceInfo, deviceFoundEventParams.vendorElemBytes, vendorData); } private void handleDeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, int configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo, @Nullable byte[] wfdR2DeviceInfo, @Nullable byte[] vendorElemBytes, @Nullable List<OuiKeyedData> vendorData) { WifiP2pDevice device = new WifiP2pDevice(); device.deviceName = deviceName; if (deviceName == null) { Log.e(TAG, "Missing device name."); return; } try { device.deviceAddress = NativeUtil.macAddressFromByteArray(p2pDeviceAddress); } catch (Exception e) { Log.e(TAG, "Could not decode device address.", e); return; } try { device.primaryDeviceType = NativeUtil.wpsDevTypeStringFromByteArray(primaryDeviceType); } catch (Exception e) { Log.e(TAG, "Could not encode device primary type.", e); return; } device.deviceCapability = deviceCapabilities; device.groupCapability = groupCapabilities; device.wpsConfigMethodsSupported = configMethods; device.status = WifiP2pDevice.AVAILABLE; if (wfdDeviceInfo != null && wfdDeviceInfo.length >= 6) { device.wfdInfo = new WifiP2pWfdInfo( ((wfdDeviceInfo[0] & 0xFF) << 8) + (wfdDeviceInfo[1] & 0xFF), ((wfdDeviceInfo[2] & 0xFF) << 8) + (wfdDeviceInfo[3] & 0xFF), ((wfdDeviceInfo[4] & 0xFF) << 8) + (wfdDeviceInfo[5] & 0xFF)); } if (wfdR2DeviceInfo != null && wfdR2DeviceInfo.length >= 2) { device.wfdInfo.setR2DeviceInfo( ((wfdR2DeviceInfo[0] & 0xFF) << 8) + (wfdR2DeviceInfo[1] & 0xFF)); } if (null != vendorElemBytes && vendorElemBytes.length > 0) { logd("Vendor Element Bytes: " + HexDump.dumpHexString(vendorElemBytes)); List<ScanResult.InformationElement> vendorElements = new ArrayList<>(); try { ByteArrayInputStream is = new ByteArrayInputStream(vendorElemBytes); int b; while ((b = is.read()) != -1) { int id = b; int len = is.read(); if (len == -1) break; byte[] bytes = new byte[len]; int read = is.read(bytes, 0, len); if (-1 == read || len != read) break; if (id != ScanResult.InformationElement.EID_VSA) continue; vendorElements.add(new ScanResult.InformationElement(id, 0, bytes)); } } catch (Exception ex) { logd("Cannot parse vendor element bytes: " + ex); vendorElements = null; } device.setVendorElements(vendorElements); } if (SdkLevel.isAtLeastV() && vendorData != null) { device.setVendorData(vendorData); } logd("Device discovered on " + mInterface + ": " + device); mMonitor.broadcastP2pDeviceFound(mInterface, device); } private static WifiP2pServiceImpl.P2pStatus halStatusToP2pStatus(int status) { WifiP2pServiceImpl.P2pStatus result = WifiP2pServiceImpl.P2pStatus.UNKNOWN; switch (status) { case P2pStatusCode.SUCCESS: case P2pStatusCode.SUCCESS_DEFERRED: result = WifiP2pServiceImpl.P2pStatus.SUCCESS; break; case P2pStatusCode.FAIL_INFO_CURRENTLY_UNAVAILABLE: result = WifiP2pServiceImpl.P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE; break; case P2pStatusCode.FAIL_INCOMPATIBLE_PARAMS: result = WifiP2pServiceImpl.P2pStatus.INCOMPATIBLE_PARAMETERS; break; case P2pStatusCode.FAIL_LIMIT_REACHED: result = WifiP2pServiceImpl.P2pStatus.LIMIT_REACHED; break; case P2pStatusCode.FAIL_INVALID_PARAMS: result = WifiP2pServiceImpl.P2pStatus.INVALID_PARAMETER; break; case P2pStatusCode.FAIL_UNABLE_TO_ACCOMMODATE: result = WifiP2pServiceImpl.P2pStatus.UNABLE_TO_ACCOMMODATE_REQUEST; break; case P2pStatusCode.FAIL_PREV_PROTOCOL_ERROR: result = WifiP2pServiceImpl.P2pStatus.PREVIOUS_PROTOCOL_ERROR; break; case P2pStatusCode.FAIL_NO_COMMON_CHANNELS: result = WifiP2pServiceImpl.P2pStatus.NO_COMMON_CHANNEL; break; case P2pStatusCode.FAIL_UNKNOWN_GROUP: result = WifiP2pServiceImpl.P2pStatus.UNKNOWN_P2P_GROUP; break; case P2pStatusCode.FAIL_BOTH_GO_INTENT_15: result = WifiP2pServiceImpl.P2pStatus.BOTH_GO_INTENT_15; break; case P2pStatusCode.FAIL_INCOMPATIBLE_PROV_METHOD: result = WifiP2pServiceImpl.P2pStatus.INCOMPATIBLE_PROVISIONING_METHOD; break; case P2pStatusCode.FAIL_REJECTED_BY_USER: result = WifiP2pServiceImpl.P2pStatus.REJECTED_BY_USER; break; } return result; } @Override public String getInterfaceHash() { return ISupplicantP2pIfaceCallback.HASH; } @Override public int getInterfaceVersion() { return ISupplicantP2pIfaceCallback.VERSION; } }