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            // TODO: validate that the client ID actually comes from the correct process and is
596            // not faked?
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.REQUEST_CHANNEL_SETUP, selectChannelForRequest(nnri),
643                        nnri.peerDiscoveryMac, nnri.interfaceName, nnri.networkSpecifier.pmk,
644                        nnri.networkSpecifier.passphrase);
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: for now simply select channel 6
785     */
786    private int selectChannelForRequest(AwareNetworkRequestInformation req) {
787        return 2437;
788    }
789
790    /**
791     * Aware network request. State object: contains network request information/state through its
792     * lifetime.
793     */
794    @VisibleForTesting
795    public static class AwareNetworkRequestInformation {
796        static final int STATE_INITIATOR_IDLE = 100;
797        static final int STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE = 101;
798        static final int STATE_INITIATOR_WAIT_FOR_CONFIRM = 102;
799        static final int STATE_INITIATOR_CONFIRMED = 103;
800
801        static final int STATE_RESPONDER_IDLE = 200;
802        static final int STATE_RESPONDER_WAIT_FOR_REQUEST = 201;
803        static final int STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE = 202;
804        static final int STATE_RESPONDER_WAIT_FOR_CONFIRM = 203;
805        static final int STATE_RESPONDER_CONFIRMED = 204;
806
807        public int state;
808
809        public int uid;
810        public String interfaceName;
811        public int pubSubId = 0;
812        public byte[] peerDiscoveryMac = null;
813        public int ndpId;
814        public byte[] peerDataMac;
815        public WifiAwareNetworkSpecifier networkSpecifier;
816
817        public WifiAwareNetworkAgent networkAgent;
818
819        static AwareNetworkRequestInformation processNetworkSpecifier(WifiAwareNetworkSpecifier ns,
820                WifiAwareStateManager mgr) {
821            int uid, pubSubId = 0;
822            byte[] peerMac = ns.peerMac;
823
824            if (VDBG) {
825                Log.v(TAG, "processNetworkSpecifier: networkSpecifier=" + ns);
826            }
827
828            // type: always valid
829            if (ns.type < 0
830                    || ns.type > WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_MAX_VALID) {
831                Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
832                        + ", invalid 'type' value");
833                return null;
834            }
835
836            // role: always valid
837            if (ns.role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
838                    && ns.role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
839                Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
840                        + " -- invalid 'role' value");
841                return null;
842            }
843
844            if (ns.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
845                    && ns.type != WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB
846                    && ns.type != WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB) {
847                Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
848                        + " -- invalid 'type' value for INITIATOR (only IB and OOB are "
849                        + "permitted)");
850                return null;
851            }
852
853            // look up network specifier information in Aware state manager
854            WifiAwareClientState client = mgr.getClient(ns.clientId);
855            if (client == null) {
856                Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
857                        + " -- not client with this id -- clientId=" + ns.clientId);
858                return null;
859            }
860            uid = client.getUid();
861
862            // validate the role (if session ID provided: i.e. session 1xx)
863            if (ns.type == WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB
864                    || ns.type == WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER) {
865                WifiAwareDiscoverySessionState session = client.getSession(ns.sessionId);
866                if (session == null) {
867                    Log.e(TAG,
868                            "processNetworkSpecifier: networkSpecifier=" + ns
869                                    + " -- no session with this id -- sessionId=" + ns.sessionId);
870                    return null;
871                }
872
873                if ((session.isPublishSession()
874                        && ns.role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) || (
875                        !session.isPublishSession() && ns.role
876                                != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)) {
877                    Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
878                            + " -- invalid role for session type");
879                    return null;
880                }
881
882                if (ns.type == WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB) {
883                    pubSubId = session.getPubSubId();
884                    String peerMacStr = session.getMac(ns.peerId, null);
885                    if (peerMacStr == null) {
886                        Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
887                                + " -- no MAC address associated with this peer id -- peerId="
888                                + ns.peerId);
889                        return null;
890                    }
891                    try {
892                        peerMac = HexEncoding.decode(peerMacStr.toCharArray(), false);
893                        if (peerMac == null || peerMac.length != 6) {
894                            Log.e(TAG, "processNetworkSpecifier: networkSpecifier="
895                                    + ns + " -- invalid peer MAC address");
896                            return null;
897                        }
898                    } catch (IllegalArgumentException e) {
899                        Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns
900                                + " -- invalid peer MAC address -- e=" + e);
901                        return null;
902                    }
903                }
904            }
905
906            // create container and populate
907            AwareNetworkRequestInformation nnri = new AwareNetworkRequestInformation();
908            nnri.state = (ns.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
909                    ? AwareNetworkRequestInformation.STATE_INITIATOR_IDLE
910                    : AwareNetworkRequestInformation.STATE_RESPONDER_IDLE;
911            nnri.uid = uid;
912            nnri.pubSubId = pubSubId;
913            nnri.peerDiscoveryMac = peerMac;
914            nnri.networkSpecifier = ns;
915
916            return nnri;
917        }
918
919        @Override
920        public String toString() {
921            StringBuilder sb = new StringBuilder("AwareNetworkRequestInformation: ");
922            sb.append("state=").append(state).append(", ns=").append(networkSpecifier).append(
923                    ", uid=").append(uid).append(", interfaceName=").append(interfaceName).append(
924                    ", pubSubId=").append(pubSubId).append(", peerDiscoveryMac=").append(
925                    peerDiscoveryMac == null ? ""
926                            : String.valueOf(HexEncoding.encode(peerDiscoveryMac))).append(
927                    ", ndpId=").append(ndpId).append(", peerDataMac=").append(
928                    peerDataMac == null ? "" : String.valueOf(HexEncoding.encode(peerDataMac)));
929            return sb.toString();
930        }
931    }
932
933    /**
934     * Enables mocking.
935     */
936    @VisibleForTesting
937    public class NetworkInterfaceWrapper {
938        /**
939         * Configures network agent properties: link-local address, connected status, interface
940         * name. Delegated to enable mocking.
941         */
942        public boolean configureAgentProperties(AwareNetworkRequestInformation nnri,
943                WifiAwareNetworkSpecifier networkSpecifier, int ndpId, NetworkInfo networkInfo,
944                NetworkCapabilities networkCapabilities, LinkProperties linkProperties) {
945            // find link-local address
946            InetAddress linkLocal = null;
947            NetworkInterface ni;
948            try {
949                ni = NetworkInterface.getByName(nnri.interfaceName);
950            } catch (SocketException e) {
951                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
952                        + ": can't get network interface - " + e);
953                mMgr.endDataPath(ndpId);
954                return false;
955            }
956            if (ni == null) {
957                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
958                        + ": can't get network interface (null)");
959                mMgr.endDataPath(ndpId);
960                return false;
961            }
962            Enumeration<InetAddress> addresses = ni.getInetAddresses();
963            while (addresses.hasMoreElements()) {
964                InetAddress ip = addresses.nextElement();
965                if (ip instanceof Inet6Address && ip.isLinkLocalAddress()) {
966                    linkLocal = ip;
967                    break;
968                }
969            }
970
971            if (linkLocal == null) {
972                Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": no link local addresses");
973                mMgr.endDataPath(ndpId);
974                return false;
975            }
976
977            // configure agent
978            networkInfo.setIsAvailable(true);
979            networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
980
981            networkCapabilities.setNetworkSpecifier(networkSpecifier);
982
983            linkProperties.setInterfaceName(nnri.interfaceName);
984            linkProperties.addLinkAddress(new LinkAddress(linkLocal, 64));
985            linkProperties.addRoute(
986                    new RouteInfo(new IpPrefix("fe80::/64"), null, nnri.interfaceName));
987
988            return true;
989        }
990    }
991
992    /**
993     * Dump the internal state of the class.
994     */
995    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
996        pw.println("WifiAwareDataPathStateManager:");
997        pw.println("  mInterfaces: " + mInterfaces);
998        pw.println("  mNetworkCapabilitiesFilter: " + mNetworkCapabilitiesFilter);
999        pw.println("  mNetworkRequestsCache: " + mNetworkRequestsCache);
1000        pw.println("  mNetworkFactory:");
1001        mNetworkFactory.dump(fd, pw, args);
1002    }
1003}
1004