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