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