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