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