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.aware;
18
19import android.hardware.wifi.V1_0.IWifiNanIfaceEventCallback;
20import android.hardware.wifi.V1_0.NanCapabilities;
21import android.hardware.wifi.V1_0.NanClusterEventInd;
22import android.hardware.wifi.V1_0.NanClusterEventType;
23import android.hardware.wifi.V1_0.NanDataPathConfirmInd;
24import android.hardware.wifi.V1_0.NanDataPathRequestInd;
25import android.hardware.wifi.V1_0.NanFollowupReceivedInd;
26import android.hardware.wifi.V1_0.NanMatchInd;
27import android.hardware.wifi.V1_0.NanStatusType;
28import android.hardware.wifi.V1_0.WifiNanStatus;
29import android.util.Log;
30
31import libcore.util.HexEncoding;
32
33import java.util.ArrayList;
34import java.util.Arrays;
35
36/**
37 * Manages the callbacks from Wi-Fi Aware HIDL (HAL).
38 */
39public class WifiAwareNativeCallback extends IWifiNanIfaceEventCallback.Stub {
40    private static final String TAG = "WifiAwareNativeCallback";
41    private static final boolean DBG = false;
42    private static final boolean VDBG = false;
43
44    private final WifiAwareStateManager mWifiAwareStateManager;
45
46    public WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager) {
47        mWifiAwareStateManager = wifiAwareStateManager;
48    }
49
50    @Override
51    public void notifyCapabilitiesResponse(short id, WifiNanStatus status,
52            NanCapabilities capabilities) {
53        if (VDBG) {
54            Log.v(TAG, "notifyCapabilitiesResponse: id=" + id + ", status=" + statusString(status)
55                    + ", capabilities=" + capabilities);
56        }
57
58        if (status.status == NanStatusType.SUCCESS) {
59            Capabilities frameworkCapabilities = new Capabilities();
60            frameworkCapabilities.maxConcurrentAwareClusters = capabilities.maxConcurrentClusters;
61            frameworkCapabilities.maxPublishes = capabilities.maxPublishes;
62            frameworkCapabilities.maxSubscribes = capabilities.maxSubscribes;
63            frameworkCapabilities.maxServiceNameLen = capabilities.maxServiceNameLen;
64            frameworkCapabilities.maxMatchFilterLen = capabilities.maxMatchFilterLen;
65            frameworkCapabilities.maxTotalMatchFilterLen = capabilities.maxTotalMatchFilterLen;
66            frameworkCapabilities.maxServiceSpecificInfoLen =
67                    capabilities.maxServiceSpecificInfoLen;
68            frameworkCapabilities.maxExtendedServiceSpecificInfoLen =
69                    capabilities.maxExtendedServiceSpecificInfoLen;
70            frameworkCapabilities.maxNdiInterfaces = capabilities.maxNdiInterfaces;
71            frameworkCapabilities.maxNdpSessions = capabilities.maxNdpSessions;
72            frameworkCapabilities.maxAppInfoLen = capabilities.maxAppInfoLen;
73            frameworkCapabilities.maxQueuedTransmitMessages =
74                    capabilities.maxQueuedTransmitFollowupMsgs;
75            frameworkCapabilities.maxSubscribeInterfaceAddresses =
76                    capabilities.maxSubscribeInterfaceAddresses;
77            frameworkCapabilities.supportedCipherSuites = capabilities.supportedCipherSuites;
78
79            mWifiAwareStateManager.onCapabilitiesUpdateResponse(id, frameworkCapabilities);
80        } else {
81            Log.e(TAG, "notifyCapabilitiesResponse: error code=" + status.status + " ("
82                    + status.description + ")");
83        }
84    }
85
86    @Override
87    public void notifyEnableResponse(short id, WifiNanStatus status) {
88        if (VDBG) Log.v(TAG, "notifyEnableResponse: id=" + id + ", status=" + statusString(status));
89
90        if (status.status == NanStatusType.SUCCESS) {
91            mWifiAwareStateManager.onConfigSuccessResponse(id);
92        } else {
93            mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
94        }
95    }
96
97    @Override
98    public void notifyConfigResponse(short id, WifiNanStatus status) {
99        if (VDBG) Log.v(TAG, "notifyConfigResponse: id=" + id + ", status=" + statusString(status));
100
101        if (status.status == NanStatusType.SUCCESS) {
102            mWifiAwareStateManager.onConfigSuccessResponse(id);
103        } else {
104            mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
105        }
106    }
107
108    @Override
109    public void notifyDisableResponse(short id, WifiNanStatus status) {
110        if (VDBG) {
111            Log.v(TAG, "notifyDisableResponse: id=" + id + ", status=" + statusString(status));
112        }
113
114        if (status.status == NanStatusType.SUCCESS) {
115            // NOP
116        } else {
117            Log.e(TAG, "notifyDisableResponse: failure - code=" + status.status + " ("
118                    + status.description + ")");
119        }
120    }
121
122    @Override
123    public void notifyStartPublishResponse(short id, WifiNanStatus status, byte publishId) {
124        if (VDBG) {
125            Log.v(TAG, "notifyStartPublishResponse: id=" + id + ", status=" + statusString(status)
126                    + ", publishId=" + publishId);
127        }
128
129        if (status.status == NanStatusType.SUCCESS) {
130            mWifiAwareStateManager.onSessionConfigSuccessResponse(id, true, publishId);
131        } else {
132            mWifiAwareStateManager.onSessionConfigFailResponse(id, true, status.status);
133        }
134    }
135
136    @Override
137    public void notifyStopPublishResponse(short id, WifiNanStatus status) {
138        if (VDBG) {
139            Log.v(TAG, "notifyStopPublishResponse: id=" + id + ", status=" + statusString(status));
140        }
141
142        if (status.status == NanStatusType.SUCCESS) {
143            // NOP
144        } else {
145            Log.e(TAG, "notifyStopPublishResponse: failure - code=" + status.status + " ("
146                    + status.description + ")");
147        }
148    }
149
150    @Override
151    public void notifyStartSubscribeResponse(short id, WifiNanStatus status, byte subscribeId) {
152        if (VDBG) {
153            Log.v(TAG, "notifyStartSubscribeResponse: id=" + id + ", status=" + statusString(status)
154                    + ", subscribeId=" + subscribeId);
155        }
156
157        if (status.status == NanStatusType.SUCCESS) {
158            mWifiAwareStateManager.onSessionConfigSuccessResponse(id, false, subscribeId);
159        } else {
160            mWifiAwareStateManager.onSessionConfigFailResponse(id, false, status.status);
161        }
162    }
163
164    @Override
165    public void notifyStopSubscribeResponse(short id, WifiNanStatus status) {
166        if (VDBG) {
167            Log.v(TAG, "notifyStopSubscribeResponse: id=" + id + ", status="
168                    + statusString(status));
169        }
170
171        if (status.status == NanStatusType.SUCCESS) {
172            // NOP
173        } else {
174            Log.e(TAG, "notifyStopSubscribeResponse: failure - code=" + status.status + " ("
175                    + status.description + ")");
176        }
177    }
178
179    @Override
180    public void notifyTransmitFollowupResponse(short id, WifiNanStatus status) {
181        if (VDBG) {
182            Log.v(TAG, "notifyTransmitFollowupResponse: id=" + id + ", status="
183                    + statusString(status));
184        }
185
186        if (status.status == NanStatusType.SUCCESS) {
187            mWifiAwareStateManager.onMessageSendQueuedSuccessResponse(id);
188        } else {
189            mWifiAwareStateManager.onMessageSendQueuedFailResponse(id, status.status);
190        }
191    }
192
193    @Override
194    public void notifyCreateDataInterfaceResponse(short id, WifiNanStatus status) {
195        if (VDBG) {
196            Log.v(TAG, "notifyCreateDataInterfaceResponse: id=" + id + ", status="
197                    + statusString(status));
198        }
199
200        mWifiAwareStateManager.onCreateDataPathInterfaceResponse(id,
201                status.status == NanStatusType.SUCCESS, status.status);
202    }
203
204    @Override
205    public void notifyDeleteDataInterfaceResponse(short id, WifiNanStatus status) {
206        if (VDBG) {
207            Log.v(TAG, "notifyDeleteDataInterfaceResponse: id=" + id + ", status="
208                    + statusString(status));
209        }
210
211        mWifiAwareStateManager.onDeleteDataPathInterfaceResponse(id,
212                status.status == NanStatusType.SUCCESS, status.status);
213    }
214
215    @Override
216    public void notifyInitiateDataPathResponse(short id, WifiNanStatus status,
217            int ndpInstanceId) {
218        if (VDBG) {
219            Log.v(TAG, "notifyInitiateDataPathResponse: id=" + id + ", status="
220                    + statusString(status) + ", ndpInstanceId=" + ndpInstanceId);
221        }
222
223        if (status.status == NanStatusType.SUCCESS) {
224            mWifiAwareStateManager.onInitiateDataPathResponseSuccess(id, ndpInstanceId);
225        } else {
226            mWifiAwareStateManager.onInitiateDataPathResponseFail(id, status.status);
227        }
228    }
229
230    @Override
231    public void notifyRespondToDataPathIndicationResponse(short id, WifiNanStatus status) {
232        if (VDBG) {
233            Log.v(TAG, "notifyRespondToDataPathIndicationResponse: id=" + id
234                    + ", status=" + statusString(status));
235        }
236
237        mWifiAwareStateManager.onRespondToDataPathSetupRequestResponse(id,
238                status.status == NanStatusType.SUCCESS, status.status);
239    }
240
241    @Override
242    public void notifyTerminateDataPathResponse(short id, WifiNanStatus status) {
243        if (VDBG) {
244            Log.v(TAG, "notifyTerminateDataPathResponse: id=" + id + ", status="
245                    + statusString(status));
246        }
247
248        mWifiAwareStateManager.onEndDataPathResponse(id, status.status == NanStatusType.SUCCESS,
249                status.status);
250    }
251
252    @Override
253    public void eventClusterEvent(NanClusterEventInd event) {
254        if (VDBG) {
255            Log.v(TAG, "eventClusterEvent: eventType=" + event.eventType + ", addr="
256                    + String.valueOf(HexEncoding.encode(event.addr)));
257        }
258
259        if (event.eventType == NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED) {
260            mWifiAwareStateManager.onInterfaceAddressChangeNotification(event.addr);
261        } else if (event.eventType == NanClusterEventType.STARTED_CLUSTER) {
262            mWifiAwareStateManager.onClusterChangeNotification(
263                    WifiAwareClientState.CLUSTER_CHANGE_EVENT_STARTED, event.addr);
264        } else if (event.eventType == NanClusterEventType.JOINED_CLUSTER) {
265            mWifiAwareStateManager.onClusterChangeNotification(
266                    WifiAwareClientState.CLUSTER_CHANGE_EVENT_JOINED, event.addr);
267        } else {
268            Log.e(TAG, "eventClusterEvent: invalid eventType=" + event.eventType);
269        }
270    }
271
272    @Override
273    public void eventDisabled(WifiNanStatus status) {
274        if (VDBG) Log.v(TAG, "eventDisabled: status=" + statusString(status));
275
276        mWifiAwareStateManager.onAwareDownNotification(status.status);
277    }
278
279    @Override
280    public void eventPublishTerminated(byte sessionId, WifiNanStatus status) {
281        if (VDBG) {
282            Log.v(TAG, "eventPublishTerminated: sessionId=" + sessionId + ", status="
283                    + statusString(status));
284        }
285
286        mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, true);
287    }
288
289    @Override
290    public void eventSubscribeTerminated(byte sessionId, WifiNanStatus status) {
291        if (VDBG) {
292            Log.v(TAG, "eventSubscribeTerminated: sessionId=" + sessionId + ", status="
293                    + statusString(status));
294        }
295
296        mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, false);
297    }
298
299    @Override
300    public void eventMatch(NanMatchInd event) {
301        if (VDBG) {
302            Log.v(TAG, "eventMatch: discoverySessionId=" + event.discoverySessionId + ", peerId="
303                    + event.peerId + ", addr=" + String.valueOf(HexEncoding.encode(event.addr))
304                    + ", serviceSpecificInfo=" + Arrays.toString(
305                    convertArrayListToNativeByteArray(event.serviceSpecificInfo)) + ", matchFilter="
306                    + Arrays.toString(convertArrayListToNativeByteArray(event.matchFilter)));
307        }
308
309        mWifiAwareStateManager.onMatchNotification(event.discoverySessionId, event.peerId,
310                event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo),
311                convertArrayListToNativeByteArray(event.matchFilter));
312    }
313
314    @Override
315    public void eventMatchExpired(byte discoverySessionId, int peerId) {
316        if (VDBG) {
317            Log.v(TAG, "eventMatchExpired: discoverySessionId=" + discoverySessionId
318                    + ", peerId=" + peerId);
319        }
320
321        // NOP
322    }
323
324    @Override
325    public void eventFollowupReceived(NanFollowupReceivedInd event) {
326        if (VDBG) {
327            Log.v(TAG, "eventFollowupReceived: discoverySessionId=" + event.discoverySessionId
328                    + ", peerId=" + event.peerId + ", addr=" + String.valueOf(
329                    HexEncoding.encode(event.addr)));
330        }
331
332        mWifiAwareStateManager.onMessageReceivedNotification(event.discoverySessionId, event.peerId,
333                event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo));
334    }
335
336    @Override
337    public void eventTransmitFollowup(short id, WifiNanStatus status) {
338        if (VDBG) {
339            Log.v(TAG, "eventTransmitFollowup: id=" + id + ", status=" + statusString(status));
340        }
341
342        if (status.status == NanStatusType.SUCCESS) {
343            mWifiAwareStateManager.onMessageSendSuccessNotification(id);
344        } else {
345            mWifiAwareStateManager.onMessageSendFailNotification(id, status.status);
346        }
347    }
348
349    @Override
350    public void eventDataPathRequest(NanDataPathRequestInd event) {
351        if (VDBG) {
352            Log.v(TAG, "eventDataPathRequest: discoverySessionId=" + event.discoverySessionId
353                    + ", peerDiscMacAddr=" + String.valueOf(
354                    HexEncoding.encode(event.peerDiscMacAddr)) + ", ndpInstanceId="
355                    + event.ndpInstanceId);
356        }
357
358        mWifiAwareStateManager.onDataPathRequestNotification(event.discoverySessionId,
359                event.peerDiscMacAddr, event.ndpInstanceId);
360    }
361
362    @Override
363    public void eventDataPathConfirm(NanDataPathConfirmInd event) {
364        if (VDBG) {
365            Log.v(TAG, "onDataPathConfirm: ndpInstanceId=" + event.ndpInstanceId
366                    + ", peerNdiMacAddr=" + String.valueOf(HexEncoding.encode(event.peerNdiMacAddr))
367                    + ", dataPathSetupSuccess=" + event.dataPathSetupSuccess + ", reason="
368                    + event.status.status);
369        }
370
371        mWifiAwareStateManager.onDataPathConfirmNotification(event.ndpInstanceId,
372                event.peerNdiMacAddr, event.dataPathSetupSuccess, event.status.status,
373                convertArrayListToNativeByteArray(event.appInfo));
374    }
375
376    @Override
377    public void eventDataPathTerminated(int ndpInstanceId) {
378        if (VDBG) Log.v(TAG, "eventDataPathTerminated: ndpInstanceId=" + ndpInstanceId);
379
380        mWifiAwareStateManager.onDataPathEndNotification(ndpInstanceId);
381    }
382
383    // utilities
384
385    /**
386     * Converts an ArrayList<Byte> to a byte[].
387     *
388     * @param from The input ArrayList<Byte></Byte> to convert from.
389     *
390     * @return A newly allocated byte[].
391     */
392    private byte[] convertArrayListToNativeByteArray(ArrayList<Byte> from) {
393        if (from == null) {
394            return null;
395        }
396
397        byte[] to = new byte[from.size()];
398        for (int i = 0; i < from.size(); ++i) {
399            to[i] = from.get(i);
400        }
401        return to;
402    }
403
404    private static String statusString(WifiNanStatus status) {
405        if (status == null) {
406            return "status=null";
407        }
408        StringBuilder sb = new StringBuilder();
409        sb.append(status.status).append(" (").append(status.description).append(")");
410        return sb.toString();
411    }
412}
413