WifiAwareDataPathStateManager.java revision 69eb934f563ac0099113bf24587c729df25b15bf
1/*
2 * Copyright (C) 2016 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.content.Context;
20import android.hardware.wifi.V1_0.NanDataPathChannelCfg;
21import android.net.ConnectivityManager;
22import android.net.IpPrefix;
23import android.net.LinkAddress;
24import android.net.LinkProperties;
25import android.net.NetworkAgent;
26import android.net.NetworkCapabilities;
27import android.net.NetworkFactory;
28import android.net.NetworkInfo;
29import android.net.NetworkRequest;
30import android.net.RouteInfo;
31import android.net.wifi.aware.WifiAwareManager;
32import android.os.IBinder;
33import android.os.INetworkManagementService;
34import android.os.Looper;
35import android.os.ServiceManager;
36import android.text.TextUtils;
37import android.util.ArrayMap;
38import android.util.Base64;
39import android.util.Log;
40
41import com.android.internal.annotations.VisibleForTesting;
42
43import libcore.util.HexEncoding;
44
45import org.json.JSONException;
46import org.json.JSONObject;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.net.Inet6Address;
51import java.net.InetAddress;
52import java.net.NetworkInterface;
53import java.net.SocketException;
54import java.util.Arrays;
55import java.util.Enumeration;
56import java.util.HashSet;
57import java.util.Iterator;
58import java.util.Map;
59import java.util.Set;
60
61/**
62 * Manages Aware data-path lifetime: interface creation/deletion, data-path setup and tear-down.
63 * The Aware network configuration is:
64 * - transport = TRANSPORT_WIFI_AWARE
65 * - capabilities = NET_CAPABILITY_NOT_VPN
66 * - network specifier generated by DiscoverySession.createNetworkSpecifier(...) or
67 *   WifiAwareManager.createNetworkSpecifier(...).
68 *   The network specifier is encoded as a JSON string with the key combos described in
69 *   {@link WifiAwareManager} as {@code NETWORK_SPECIFIER_TYPE_*}.
70 */
71public class WifiAwareDataPathStateManager {
72    private static final String TAG = "WifiAwareDataPathStMgr";
73
74    private static final boolean DBG = false;
75    private static final boolean VDBG = false; // STOPSHIP if true
76
77    private static final String AWARE_INTERFACE_PREFIX = "aware_data";
78    private static final String NETWORK_TAG = "WIFI_AWARE_FACTORY";
79    private static final String AGENT_TAG_PREFIX = "WIFI_AWARE_AGENT_";
80    private static final int NETWORK_FACTORY_SCORE_AVAIL = 1;
81    private static final int NETWORK_FACTORY_BANDWIDTH_AVAIL = 1;
82    private static final int NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL = 1;
83
84    private final WifiAwareStateManager mMgr;
85    private final NetworkInterfaceWrapper mNiWrapper = new NetworkInterfaceWrapper();
86    private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
87    private final Set<String> mInterfaces = new HashSet<>();
88    private final Map<String, AwareNetworkRequestInformation> mNetworkRequestsCache =
89            new ArrayMap<>();
90    private Context mContext;
91    private Looper mLooper;
92    private WifiAwareNetworkFactory mNetworkFactory;
93    private INetworkManagementService mNwService;
94
95    public WifiAwareDataPathStateManager(WifiAwareStateManager mgr) {
96        mMgr = mgr;
97    }
98
99    /**
100     * Initialize the Aware data-path state manager. Specifically register the network factory with
101     * connectivity service.
102     */
103    public void start(Context context, Looper looper) {
104        if (VDBG) Log.v(TAG, "start");
105
106        mContext = context;
107        mLooper = looper;
108
109        mNetworkCapabilitiesFilter.clearAll();
110        mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
111        mNetworkCapabilitiesFilter
112                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
113                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
114                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
115                .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
116        mNetworkCapabilitiesFilter
117                .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
118        mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
119        mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
120        mNetworkCapabilitiesFilter.setSignalStrength(NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL);
121
122        mNetworkFactory = new WifiAwareNetworkFactory(looper, context, mNetworkCapabilitiesFilter);
123        mNetworkFactory.setScoreFilter(NETWORK_FACTORY_SCORE_AVAIL);
124        mNetworkFactory.register();
125
126        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
127        mNwService = INetworkManagementService.Stub.asInterface(b);
128    }
129
130    private Map.Entry<String, AwareNetworkRequestInformation> getNetworkRequestByNdpId(int ndpId) {
131        for (Map.Entry<String, AwareNetworkRequestInformation> entry : mNetworkRequestsCache
132                .entrySet()) {
133            if (entry.getValue().ndpId == ndpId) {
134                return entry;
135            }
136        }
137
138        return null;
139    }
140
141    /**
142     * Create all Aware data-path interfaces which are possible on the device - based on the
143     * capabilities of the firmware.
144     */
145    public void createAllInterfaces() {
146        if (VDBG) Log.v(TAG, "createAllInterfaces");
147
148        if (mMgr.getCapabilities() == null) {
149            Log.e(TAG, "createAllInterfaces: capabilities aren't initialized yet!");
150            return;
151        }
152
153        for (int i = 0; i < mMgr.getCapabilities().maxNdiInterfaces; ++i) {
154            String name = AWARE_INTERFACE_PREFIX + i;
155            if (mInterfaces.contains(name)) {
156                Log.e(TAG, "createAllInterfaces(): interface already up, " + name
157                        + ", possibly failed to delete - deleting/creating again to be safe");
158                mMgr.deleteDataPathInterface(name);
159
160                // critical to remove so that don't get infinite loop if the delete fails again
161                mInterfaces.remove(name);
162            }
163
164            mMgr.createDataPathInterface(name);
165        }
166    }
167
168    /**
169     * Delete all Aware data-path interfaces which are currently up.
170     */
171    public void deleteAllInterfaces() {
172        if (VDBG) Log.v(TAG, "deleteAllInterfaces");
173
174        for (String name : mInterfaces) {
175            mMgr.deleteDataPathInterface(name);
176        }
177    }
178
179    /**
180     * Called when firmware indicates the an interface was created.
181     */
182    public void onInterfaceCreated(String interfaceName) {
183        if (VDBG) Log.v(TAG, "onInterfaceCreated: interfaceName=" + interfaceName);
184
185        if (mInterfaces.contains(interfaceName)) {
186            Log.w(TAG, "onInterfaceCreated: already contains interface -- " + interfaceName);
187        }
188
189        mInterfaces.add(interfaceName);
190    }
191
192    /**
193     * Called when firmware indicates the an interface was deleted.
194     */
195    public void onInterfaceDeleted(String interfaceName) {
196        if (VDBG) Log.v(TAG, "onInterfaceDeleted: interfaceName=" + interfaceName);
197
198        if (!mInterfaces.contains(interfaceName)) {
199            Log.w(TAG, "onInterfaceDeleted: interface not on list -- " + interfaceName);
200        }
201
202        mInterfaces.remove(interfaceName);
203    }
204
205    /**
206     * Response to initiating data-path request. Indicates that request is successful (not
207     * complete!) and is now in progress.
208     *
209     * @param networkSpecifier The network specifier provided as part of the initiate request.
210     * @param ndpId            The ID assigned to the data-path.
211     */
212    public void onDataPathInitiateSuccess(String networkSpecifier, int ndpId) {
213        if (VDBG) {
214            Log.v(TAG,
215                    "onDataPathInitiateSuccess: networkSpecifier=" + networkSpecifier + ", ndpId="
216                            + ndpId);
217        }
218
219        AwareNetworkRequestInformation nnri = mNetworkRequestsCache.get(networkSpecifier);
220        if (nnri == null) {
221            Log.w(TAG, "onDataPathInitiateSuccess: network request not found for networkSpecifier="
222                    + networkSpecifier);
223            mMgr.endDataPath(ndpId);
224            return;
225        }
226
227        if (nnri.state
228                != AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE) {
229            Log.w(TAG, "onDataPathInitiateSuccess: network request in incorrect state: state="
230                    + nnri.state);
231            mNetworkRequestsCache.remove(networkSpecifier);
232            mMgr.endDataPath(ndpId);
233            return;
234        }
235
236        nnri.state = AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_CONFIRM;
237        nnri.ndpId = ndpId;
238    }
239
240    /**
241     * Response to an attempt to set up a data-path (on the initiator side).
242     *
243     * @param networkSpecifier The network specifier provided as part of the initiate request.
244     * @param reason           Failure reason.
245     */
246    public void onDataPathInitiateFail(String networkSpecifier, int reason) {
247        if (VDBG) {
248            Log.v(TAG,
249                    "onDataPathInitiateFail: networkSpecifier=" + networkSpecifier + ", reason="
250                            + reason);
251        }
252
253        AwareNetworkRequestInformation nnri = mNetworkRequestsCache.remove(networkSpecifier);
254        if (nnri == null) {
255            Log.w(TAG, "onDataPathInitiateFail: network request not found for networkSpecifier="
256                    + networkSpecifier);
257            return;
258        }
259
260        if (nnri.state
261                != AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE) {
262            Log.w(TAG, "onDataPathInitiateFail: network request in incorrect state: state="
263                    + nnri.state);
264        }
265
266        mNetworkRequestsCache.remove(networkSpecifier);
267    }
268
269
270    /**
271     * Notification (unsolicited/asynchronous) that a peer has requested to set up a data-path
272     * connection with us.
273     *
274     * @param pubSubId      The ID of the discovery session context for the data-path - or 0 if not
275     *                      related to a discovery session.
276     * @param mac           The discovery MAC address of the peer.
277     * @param ndpId         The locally assigned ID for the data-path.
278     * @return The network specifier of the data-path (or null if none/error)
279     */
280    public String onDataPathRequest(int pubSubId, byte[] mac, int ndpId) {
281        if (VDBG) {
282            Log.v(TAG,
283                    "onDataPathRequest: pubSubId=" + pubSubId + ", mac=" + String.valueOf(
284                            HexEncoding.encode(mac)) + ", ndpId=" + ndpId);
285        }
286
287        String networkSpecifier = null;
288        AwareNetworkRequestInformation nnri = null;
289        for (Map.Entry<String, AwareNetworkRequestInformation> entry : mNetworkRequestsCache
290                .entrySet()) {
291            /*
292             * Checking that the incoming request (from the Initiator) matches the request
293             * we (the Responder) already have set up. The rules are:
294             * - The discovery session (pub/sub ID) must match.
295             * - The peer MAC address (if specified - i.e. non-null) must match. A null peer MAC ==
296             *   accept (otherwise matching) requests from any peer MAC.
297             */
298            if (entry.getValue().pubSubId != 0 && entry.getValue().pubSubId != pubSubId) {
299                continue;
300            }
301
302            if (entry.getValue().peerDiscoveryMac != null && !Arrays.equals(
303                    entry.getValue().peerDiscoveryMac, mac)) {
304                continue;
305            }
306
307            networkSpecifier = entry.getKey();
308            nnri = entry.getValue();
309            break;
310        }
311
312        if (nnri == null) {
313            Log.w(TAG, "onDataPathRequest: can't find a request with specified pubSubId=" + pubSubId
314                    + ", mac=" + String.valueOf(HexEncoding.encode(mac)));
315            if (DBG) {
316                Log.d(TAG, "onDataPathRequest: network request cache = " + mNetworkRequestsCache);
317            }
318            mMgr.respondToDataPathRequest(false, ndpId, "", null);
319            return null;
320        }
321
322        if (nnri.state != AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST) {
323            Log.w(TAG, "onDataPathRequest: request " + networkSpecifier + " is incorrect state="
324                    + nnri.state);
325            mMgr.respondToDataPathRequest(false, ndpId, "", null);
326            mNetworkRequestsCache.remove(networkSpecifier);
327            return null;
328        }
329
330        nnri.state = AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE;
331        nnri.ndpId = ndpId;
332        nnri.interfaceName = selectInterfaceForRequest(nnri);
333        mMgr.respondToDataPathRequest(true, ndpId, nnri.interfaceName, nnri.pmk);
334
335        return networkSpecifier;
336    }
337
338    /**
339     * Called on the RESPONDER when the response to data-path request has been completed.
340     *
341     * @param ndpId The ID of the data-path (NDP)
342     * @param success Whether or not the 'RespondToDataPathRequest' operation was a success.
343     */
344    public void onRespondToDataPathRequest(int ndpId, boolean success) {
345        if (VDBG) {
346            Log.v(TAG, "onRespondToDataPathRequest: ndpId=" + ndpId + ", success=" + success);
347        }
348
349        String networkSpecifier = null;
350        AwareNetworkRequestInformation nnri = null;
351        for (Map.Entry<String, AwareNetworkRequestInformation> entry : mNetworkRequestsCache
352                .entrySet()) {
353            if (entry.getValue().ndpId == ndpId) {
354                networkSpecifier = entry.getKey();
355                nnri = entry.getValue();
356                break;
357            }
358        }
359
360        if (nnri == null) {
361            Log.w(TAG, "onRespondToDataPathRequest: can't find a request with specified ndpId="
362                    + ndpId);
363            if (DBG) {
364                Log.d(TAG, "onRespondToDataPathRequest: network request cache = "
365                        + mNetworkRequestsCache);
366            }
367            return;
368        }
369
370        if (!success) {
371            Log.w(TAG, "onRespondToDataPathRequest: request " + networkSpecifier
372                    + " failed responding");
373            mMgr.endDataPath(ndpId);
374            mNetworkRequestsCache.remove(networkSpecifier);
375            return;
376        }
377
378        if (nnri.state
379                != AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE) {
380            Log.w(TAG, "onRespondToDataPathRequest: request " + networkSpecifier
381                    + " is incorrect state=" + nnri.state);
382            mMgr.endDataPath(ndpId);
383            mNetworkRequestsCache.remove(networkSpecifier);
384            return;
385        }
386
387        nnri.state = AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_CONFIRM;
388    }
389
390    /**
391     * Notification (unsolicited/asynchronous) that the data-path (which we've been setting up)
392     * is possibly (if {@code accept} is {@code true}) ready for use from the firmware's
393     * perspective - now can do L3 configuration.
394     *
395     * @param ndpId         Id of the data-path
396     * @param mac           The MAC address of the peer's data-path (not discovery interface). Only
397     *                      valid
398     *                      if {@code accept} is {@code true}.
399     * @param accept        Indicates whether the data-path setup has succeeded (been accepted) or
400     *                      failed (been rejected).
401     * @param reason        If {@code accept} is {@code false} provides a reason code for the
402     *                      rejection/failure.
403     * @param message       The message provided by the peer as part of the data-path setup
404     *                      process.
405     * @return The network specifier of the data-path or a null if none/error.
406     */
407    public String onDataPathConfirm(int ndpId, byte[] mac, boolean accept, int reason,
408            byte[] message) {
409        if (VDBG) {
410            Log.v(TAG, "onDataPathConfirm: ndpId=" + ndpId + ", mac=" + String.valueOf(
411                    HexEncoding.encode(mac)) + ", accept=" + accept + ", reason=" + reason);
412        }
413
414        Map.Entry<String, AwareNetworkRequestInformation> nnriE = getNetworkRequestByNdpId(ndpId);
415        if (nnriE == null) {
416            Log.w(TAG, "onDataPathConfirm: network request not found for ndpId=" + ndpId);
417            if (accept) {
418                mMgr.endDataPath(ndpId);
419            }
420            return null;
421        }
422
423        String networkSpecifier = nnriE.getKey();
424        AwareNetworkRequestInformation nnri = nnriE.getValue();
425
426        // validate state
427        if (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
428                && nnri.state != AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_CONFIRM) {
429            Log.w(TAG, "onDataPathConfirm: INITIATOR in invalid state=" + nnri.state);
430            mNetworkRequestsCache.remove(networkSpecifier);
431            if (accept) {
432                mMgr.endDataPath(ndpId);
433            }
434            return networkSpecifier;
435        }
436        if (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
437                && nnri.state != AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_CONFIRM) {
438            Log.w(TAG, "onDataPathConfirm: RESPONDER in invalid state=" + nnri.state);
439            mNetworkRequestsCache.remove(networkSpecifier);
440            if (accept) {
441                mMgr.endDataPath(ndpId);
442            }
443            return networkSpecifier;
444        }
445
446        if (accept) {
447            nnri.state = (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
448                    ? AwareNetworkRequestInformation.STATE_INITIATOR_CONFIRMED
449                    : AwareNetworkRequestInformation.STATE_RESPONDER_CONFIRMED;
450            nnri.peerDataMac = mac;
451
452            NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0,
453                    NETWORK_TAG, "");
454            NetworkCapabilities networkCapabilities = new NetworkCapabilities(
455                    mNetworkCapabilitiesFilter);
456            LinkProperties linkProperties = new LinkProperties();
457
458            try {
459                mNwService.setInterfaceUp(nnri.interfaceName);
460                mNwService.enableIpv6(nnri.interfaceName);
461            } catch (Exception e) { // NwService throws runtime exceptions for errors
462                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": can't configure network - "
463                        + e);
464                mMgr.endDataPath(ndpId);
465                return networkSpecifier;
466            }
467
468            if (!mNiWrapper.configureAgentProperties(nnri, networkSpecifier, ndpId, networkInfo,
469                    networkCapabilities, linkProperties)) {
470                return networkSpecifier;
471            }
472
473            nnri.networkAgent = new WifiAwareNetworkAgent(mLooper, mContext,
474                    AGENT_TAG_PREFIX + nnri.ndpId,
475                    new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORK_TAG, ""),
476                    networkCapabilities, new LinkProperties(), NETWORK_FACTORY_SCORE_AVAIL,
477                    networkSpecifier, ndpId);
478            nnri.networkAgent.sendNetworkInfo(networkInfo);
479            nnri.networkAgent.sendLinkProperties(linkProperties);
480        } else {
481            if (DBG) {
482                Log.d(TAG, "onDataPathConfirm: data-path for networkSpecifier=" + networkSpecifier
483                        + " rejected - reason=" + reason);
484            }
485            mNetworkRequestsCache.remove(networkSpecifier);
486        }
487
488        return networkSpecifier;
489    }
490
491    /**
492     * Notification (unsolicited/asynchronous) from the firmware that the specified data-path has
493     * been terminated.
494     *
495     * @param ndpId The ID of the terminated data-path.
496     */
497    public void onDataPathEnd(int ndpId) {
498        if (VDBG) Log.v(TAG, "onDataPathEnd: ndpId=" + ndpId);
499
500        Map.Entry<String, AwareNetworkRequestInformation> nnriE = getNetworkRequestByNdpId(ndpId);
501        if (nnriE == null) {
502            if (DBG) {
503                Log.d(TAG, "onDataPathEnd: network request not found for ndpId=" + ndpId);
504            }
505            return;
506        }
507
508        tearDownInterface(nnriE.getValue());
509        mNetworkRequestsCache.remove(nnriE.getKey());
510    }
511
512    /**
513     * Called whenever Aware comes down. Clean up all pending and up network requeests and agents.
514     */
515    public void onAwareDownCleanupDataPaths() {
516        if (VDBG) Log.v(TAG, "onAwareDownCleanupDataPaths");
517
518        for (AwareNetworkRequestInformation nnri : mNetworkRequestsCache.values()) {
519            tearDownInterface(nnri);
520        }
521        mNetworkRequestsCache.clear();
522    }
523
524    /**
525     * Called when timed-out waiting for confirmation of the data-path setup (i.e.
526     * onDataPathConfirm). Started on the initiator when executing the request for the data-path
527     * and on the responder when received a request for data-path (in both cases only on success
528     * - i.e. when we're proceeding with data-path setup).
529     */
530    public void handleDataPathTimeout(String networkSpecifier) {
531        if (VDBG) Log.v(TAG, "handleDataPathTimeout: networkSpecifier=" + networkSpecifier);
532
533        AwareNetworkRequestInformation nnri = mNetworkRequestsCache.remove(networkSpecifier);
534        if (nnri == null) {
535            if (DBG) {
536                Log.d(TAG,
537                        "handleDataPathTimeout: network request not found for networkSpecifier="
538                                + networkSpecifier);
539            }
540            return;
541        }
542
543        mMgr.endDataPath(nnri.ndpId);
544    }
545
546    private class WifiAwareNetworkFactory extends NetworkFactory {
547        WifiAwareNetworkFactory(Looper looper, Context context, NetworkCapabilities filter) {
548            super(looper, context, NETWORK_TAG, filter);
549        }
550
551        @Override
552        public boolean acceptRequest(NetworkRequest request, int score) {
553            if (VDBG) {
554                Log.v(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request + ", score="
555                        + score);
556            }
557
558            if (!mMgr.isUsageEnabled()) {
559                if (VDBG) {
560                    Log.v(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
561                            + " -- Aware disabled");
562                }
563                return false;
564            }
565
566            if (mInterfaces.isEmpty()) {
567                Log.w(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
568                        + " -- No Aware interfaces are up");
569                return false;
570            }
571
572            String networkSpecifier = request.networkCapabilities.getNetworkSpecifier();
573            if (TextUtils.isEmpty(networkSpecifier)) {
574                Log.w(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
575                        + " - empty (or null) NetworkSpecifier");
576                return false;
577            }
578
579            // look up specifier - are we being called again?
580            AwareNetworkRequestInformation nnri = mNetworkRequestsCache.get(networkSpecifier);
581            if (nnri != null) {
582                if (DBG) {
583                    Log.d(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
584                            + " - already in cache!?");
585                }
586
587                // seems to happen after a network agent is created - trying to rematch all
588                // requests again!?
589                return true;
590            }
591
592            // parse network specifier (JSON) & cache
593            // TODO: validate that the client ID actually comes from the correct process and is
594            // not faked?
595            nnri = AwareNetworkRequestInformation.parseNetworkSpecifier(networkSpecifier, mMgr);
596            if (nnri == null) {
597                Log.e(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
598                        + " - can't parse network specifier");
599                return false;
600            }
601            mNetworkRequestsCache.put(networkSpecifier, nnri);
602
603            return true;
604        }
605
606        @Override
607        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
608            if (VDBG) {
609                Log.v(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
610                        + networkRequest + ", score=" + score);
611            }
612
613            String networkSpecifier = networkRequest.networkCapabilities.getNetworkSpecifier();
614            AwareNetworkRequestInformation nnri = mNetworkRequestsCache.get(networkSpecifier);
615            if (nnri == null) {
616                Log.e(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
617                        + networkRequest + " not in cache!?");
618                return;
619            }
620
621            if (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
622                if (nnri.state != AwareNetworkRequestInformation.STATE_INITIATOR_IDLE) {
623                    if (DBG) {
624                        Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
625                                + networkRequest + " - already in progress");
626                        // TODO: understand how/when can be called again/while in progress (seems
627                        // to be related to score re-calculation after a network agent is created)
628                    }
629                    return;
630                }
631
632                nnri.interfaceName = selectInterfaceForRequest(nnri);
633                mMgr.initiateDataPathSetup(networkSpecifier, nnri.peerId,
634                        NanDataPathChannelCfg.REQUEST_CHANNEL_SETUP, selectChannelForRequest(nnri),
635                        nnri.peerDiscoveryMac, nnri.interfaceName, nnri.pmk);
636                nnri.state =
637                        AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE;
638            } else {
639                if (nnri.state != AwareNetworkRequestInformation.STATE_RESPONDER_IDLE) {
640                    if (DBG) {
641                        Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
642                                + networkRequest + " - already in progress");
643                        // TODO: understand how/when can be called again/while in progress (seems
644                        // to be related to score re-calculation after a network agent is created)
645                    }
646                    return;
647                }
648
649                nnri.state = AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST;
650            }
651        }
652
653        @Override
654        protected void releaseNetworkFor(NetworkRequest networkRequest) {
655            if (VDBG) {
656                Log.v(TAG, "WifiAwareNetworkFactory.releaseNetworkFor: networkRequest="
657                        + networkRequest);
658            }
659
660            String networkSpecifier = networkRequest.networkCapabilities.getNetworkSpecifier();
661            AwareNetworkRequestInformation nnri = mNetworkRequestsCache.get(networkSpecifier);
662            if (nnri == null) {
663                Log.e(TAG, "WifiAwareNetworkFactory.releaseNetworkFor: networkRequest="
664                        + networkRequest + " not in cache!?");
665                return;
666            }
667
668            if (nnri.networkAgent != null) {
669                if (VDBG) {
670                    Log.v(TAG, "WifiAwareNetworkFactory.releaseNetworkFor: networkRequest="
671                            + networkRequest + ", nnri=" + nnri
672                            + ": agent already created - deferring ending data-path to agent"
673                            + ".unwanted()");
674                }
675                return;
676            }
677
678            if (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && nnri.state
679                    > AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE) {
680                mMgr.endDataPath(nnri.ndpId);
681            }
682            if (nnri.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER && nnri.state
683                    > AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST) {
684                mMgr.endDataPath(nnri.ndpId);
685            }
686
687            // Will get a callback (on both initiator and responder) when data-path actually
688            // terminated. At that point will inform the agent and will clear the cache.
689        }
690    }
691
692    private class WifiAwareNetworkAgent extends NetworkAgent {
693        private NetworkInfo mNetworkInfo;
694        private String mNetworkSpecifier;
695        private int mNdpId;
696
697        WifiAwareNetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
698                NetworkCapabilities nc, LinkProperties lp, int score, String networkSpecifier,
699                int ndpId) {
700            super(looper, context, logTag, ni, nc, lp, score);
701
702            mNetworkInfo = ni;
703            mNetworkSpecifier = networkSpecifier;
704            mNdpId = ndpId;
705        }
706
707        @Override
708        protected void unwanted() {
709            if (VDBG) {
710                Log.v(TAG, "WifiAwareNetworkAgent.unwanted: networkSpecifier=" + mNetworkSpecifier
711                        + ", ndpId=" + mNdpId);
712            }
713
714            mMgr.endDataPath(mNdpId);
715
716            // Will get a callback (on both initiator and responder) when data-path actually
717            // terminated. At that point will inform the agent and will clear the cache.
718        }
719
720        void reconfigureAgentAsDisconnected() {
721            if (VDBG) {
722                Log.v(TAG, "WifiAwareNetworkAgent.reconfigureAgentAsDisconnected: networkSpecifier="
723                        + mNetworkSpecifier + ", ndpId=" + mNdpId);
724            }
725
726            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, "");
727            sendNetworkInfo(mNetworkInfo);
728        }
729    }
730
731    private void tearDownInterface(AwareNetworkRequestInformation nnri) {
732        if (VDBG) Log.v(TAG, "tearDownInterface: nnri=" + nnri);
733
734        if (nnri.interfaceName != null && !nnri.interfaceName.isEmpty()) {
735            try {
736                mNwService.setInterfaceDown(nnri.interfaceName);
737            } catch (Exception e) { // NwService throws runtime exceptions for errors
738                Log.e(TAG,
739                        "tearDownInterface: nnri=" + nnri + ": can't bring interface down - " + e);
740            }
741        }
742
743        if (nnri.networkAgent != null) {
744            nnri.networkAgent.reconfigureAgentAsDisconnected();
745        }
746    }
747
748    /**
749     * Select one of the existing interfaces for the new network request.
750     *
751     * TODO: for now there is only a single interface - simply pick it.
752     */
753    private String selectInterfaceForRequest(AwareNetworkRequestInformation req) {
754        Iterator<String> it = mInterfaces.iterator();
755        if (it.hasNext()) {
756            return it.next();
757        }
758
759        Log.e(TAG, "selectInterfaceForRequest: req=" + req + " - but no interfaces available!");
760
761        return "";
762    }
763
764    /**
765     * Select a channel for the network request.
766     *
767     * TODO: for now simply select channel 6
768     */
769    private int selectChannelForRequest(AwareNetworkRequestInformation req) {
770        return 2437;
771    }
772
773    /**
774     * Aware network request. State object: contains network request information/state through its
775     * lifetime.
776     */
777    @VisibleForTesting
778    public static class AwareNetworkRequestInformation {
779        static final int STATE_INITIATOR_IDLE = 100;
780        static final int STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE = 101;
781        static final int STATE_INITIATOR_WAIT_FOR_CONFIRM = 102;
782        static final int STATE_INITIATOR_CONFIRMED = 103;
783
784        static final int STATE_RESPONDER_IDLE = 200;
785        static final int STATE_RESPONDER_WAIT_FOR_REQUEST = 201;
786        static final int STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE = 202;
787        static final int STATE_RESPONDER_WAIT_FOR_CONFIRM = 203;
788        static final int STATE_RESPONDER_CONFIRMED = 204;
789
790        public int state;
791        public int role;
792
793        public int uid;
794        public String interfaceName;
795        public int pubSubId = 0;
796        public int peerId = 0;
797        public byte[] peerDiscoveryMac = null;
798        public byte[] pmk = null;
799        public int ndpId;
800        public byte[] peerDataMac;
801
802        public WifiAwareNetworkAgent networkAgent;
803
804        static AwareNetworkRequestInformation parseNetworkSpecifier(String networkSpecifier,
805                WifiAwareStateManager mgr) {
806            int type, role, uid, clientId, sessionId = 0, peerId = 0, pubSubId = 0;
807            byte[] peerMac = null;
808            byte[] pmk = null;
809
810            if (VDBG) {
811                Log.v(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier);
812            }
813
814            try {
815                JSONObject jsonObject = new JSONObject(networkSpecifier);
816
817                // type: always present
818                type = jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_TYPE);
819                if (type < 0 || type > WifiAwareManager.NETWORK_SPECIFIER_TYPE_MAX_VALID) {
820                    Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
821                            + ", invalid 'type' value");
822                    return null;
823                }
824
825                // role: always present
826                role = jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE);
827                if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
828                        && role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
829                    Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
830                            + " -- invalid 'role' value");
831                    return null;
832                }
833
834                if (role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
835                        && type != WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB
836                        && type != WifiAwareManager.NETWORK_SPECIFIER_TYPE_OOB) {
837                    Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
838                            + " -- invalid 'type' value for INITIATOR (only IB and OOB are "
839                            + "permitted)");
840                    return null;
841                }
842
843                // clientId: always present
844                clientId = jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID);
845
846                // sessionId: present for types IB, IB_ANY_PEER
847                if (type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB
848                        || type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER) {
849                    sessionId = jsonObject.getInt(
850                            WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID);
851                }
852
853                // peer Id: present for type IB
854                if (type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB) {
855                    peerId = jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID);
856                }
857
858                // peerMac: present for type OOB
859                if (type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_OOB) {
860                    try {
861                        peerMac = HexEncoding.decode(jsonObject.getString(
862                                WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
863                                false);
864                        if (peerMac == null || peerMac.length != 6) {
865                            Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
866                                    + " -- invalid peer MAC address - null or not 6 bytes");
867                            return null;
868                        }
869                    } catch (IllegalArgumentException e) {
870                        Log.e(TAG, "parseNetworkSpecifier: networkSpecifier="
871                                + networkSpecifier + " -- invalid peer MAC address -- e=" + e);
872                        return null;
873                    }
874                }
875
876                // pmk: always present (though can be an empty array - equivalent to null)
877                pmk = Base64.decode(
878                        jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK),
879                        Base64.DEFAULT);
880                if (pmk != null && pmk.length == 0) {
881                    pmk = null;
882                }
883            } catch (JSONException e) {
884                Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
885                        + " -- invalid JSON format -- e=" + e);
886                return null;
887            }
888
889            // look up network specifier information in Aware state manager
890            WifiAwareClientState client = mgr.getClient(clientId);
891            if (client == null) {
892                Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
893                        + " -- not client with this id -- clientId=" + clientId);
894                return null;
895            }
896            uid = client.getUid();
897
898            // validate the role (if session ID provided: i.e. session 1xx)
899            if (type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB
900                    || type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER) {
901                WifiAwareDiscoverySessionState session = client.getSession(sessionId);
902                if (session == null) {
903                    Log.e(TAG,
904                            "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
905                                    + " -- no session with this id -- sessionId=" + sessionId);
906                    return null;
907                }
908
909                if ((session.isPublishSession()
910                        && role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) || (
911                        !session.isPublishSession()
912                                && role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)) {
913                    Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
914                            + " -- invalid role for session type");
915                    return null;
916                }
917
918                if (type == WifiAwareManager.NETWORK_SPECIFIER_TYPE_IB) {
919                    pubSubId = session.getPubSubId();
920                    String peerMacStr = session.getMac(peerId, null);
921                    if (peerMacStr == null) {
922                        Log.e(TAG, "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
923                                + " -- no MAC address associated with this peer id -- peerId="
924                                + peerId);
925                        return null;
926                    }
927                    try {
928                        peerMac = HexEncoding.decode(peerMacStr.toCharArray(), false);
929                        if (peerMac == null || peerMac.length != 6) {
930                            Log.e(TAG, "parseNetworkSpecifier: networkSpecifier="
931                                    + networkSpecifier + " -- invalid peer MAC address");
932                            return null;
933                        }
934                    } catch (IllegalArgumentException e) {
935                        Log.e(TAG,
936                                "parseNetworkSpecifier: networkSpecifier=" + networkSpecifier
937                                        + " -- invalid peer MAC address -- e=" + e);
938                        return null;
939                    }
940                }
941            }
942
943            // create container and populate
944            AwareNetworkRequestInformation nnri = new AwareNetworkRequestInformation();
945            nnri.state = (role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
946                    ? AwareNetworkRequestInformation.STATE_INITIATOR_IDLE
947                    : AwareNetworkRequestInformation.STATE_RESPONDER_IDLE;
948            nnri.role = role;
949            nnri.uid = uid;
950            nnri.pubSubId = pubSubId;
951            nnri.peerId = peerId;
952            nnri.peerDiscoveryMac = peerMac;
953            nnri.pmk = pmk;
954
955            return nnri;
956        }
957
958        @Override
959        public String toString() {
960            StringBuilder sb = new StringBuilder("AwareNetworkRequestInformation: ");
961            sb.append("state=").append(state).append(", role=").append(role).append(
962                    ", uid=").append(uid).append(", interfaceName=").append(interfaceName).append(
963                    ", pubSubId=").append(pubSubId).append(", peerDiscoveryMac=").append(
964                    peerDiscoveryMac == null ? ""
965                            : String.valueOf(HexEncoding.encode(peerDiscoveryMac))).append(
966                    ", ndpId=").append(ndpId).append(", peerDataMac=").append(
967                    peerDataMac == null ? "" : String.valueOf(HexEncoding.encode(peerDataMac)));
968            return sb.toString();
969        }
970    }
971
972    /**
973     * Enables mocking.
974     */
975    @VisibleForTesting
976    public class NetworkInterfaceWrapper {
977        /**
978         * Configures network agent properties: link-local address, connected status, interface
979         * name. Delegated to enable mocking.
980         */
981        public boolean configureAgentProperties(AwareNetworkRequestInformation nnri,
982                String networkSpecifier, int ndpId, NetworkInfo networkInfo,
983                NetworkCapabilities networkCapabilities, LinkProperties linkProperties) {
984            // find link-local address
985            InetAddress linkLocal = null;
986            NetworkInterface ni;
987            try {
988                ni = NetworkInterface.getByName(nnri.interfaceName);
989            } catch (SocketException e) {
990                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
991                        + ": can't get network interface - " + e);
992                mMgr.endDataPath(ndpId);
993                return false;
994            }
995            if (ni == null) {
996                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
997                        + ": can't get network interface (null)");
998                mMgr.endDataPath(ndpId);
999                return false;
1000            }
1001            Enumeration<InetAddress> addresses = ni.getInetAddresses();
1002            while (addresses.hasMoreElements()) {
1003                InetAddress ip = addresses.nextElement();
1004                if (ip instanceof Inet6Address && ip.isLinkLocalAddress()) {
1005                    linkLocal = ip;
1006                    break;
1007                }
1008            }
1009
1010            if (linkLocal == null) {
1011                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": no link local addresses");
1012                mMgr.endDataPath(ndpId);
1013                return false;
1014            }
1015
1016            // configure agent
1017            networkInfo.setIsAvailable(true);
1018            networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
1019
1020            networkCapabilities.setNetworkSpecifier(networkSpecifier);
1021
1022            linkProperties.setInterfaceName(nnri.interfaceName);
1023            linkProperties.addLinkAddress(new LinkAddress(linkLocal, 64));
1024            linkProperties.addRoute(
1025                    new RouteInfo(new IpPrefix("fe80::/64"), null, nnri.interfaceName));
1026
1027            return true;
1028        }
1029    }
1030
1031    /**
1032     * Dump the internal state of the class.
1033     */
1034    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1035        pw.println("WifiAwareDataPathStateManager:");
1036        pw.println("  mInterfaces: " + mInterfaces);
1037        pw.println("  mNetworkCapabilitiesFilter: " + mNetworkCapabilitiesFilter);
1038        pw.println("  mNetworkRequestsCache: " + mNetworkRequestsCache);
1039        pw.println("  mNetworkFactory:");
1040        mNetworkFactory.dump(fd, pw, args);
1041    }
1042}
1043