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