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