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