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