1 /* 2 * Copyright (C) 2018 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 17 package android.net.wifi; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 import static com.android.internal.util.Preconditions.checkState; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.net.MacAddress; 25 import android.net.MatchAllNetworkSpecifier; 26 import android.net.NetworkRequest; 27 import android.net.NetworkSpecifier; 28 import android.net.wifi.ScanResult.WifiBand; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 32 import java.util.Objects; 33 34 /** 35 * Network specifier object used by wifi's {@link android.net.NetworkAgent}. 36 * @hide 37 */ 38 public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable { 39 /** 40 * Security credentials for the currently connected network. 41 */ 42 private final WifiConfiguration mWifiConfiguration; 43 44 /** 45 * Band, as one of the ScanResult.WIFI_BAND_* constants. 46 */ 47 @WifiBand private final int mBand; 48 49 /** 50 * Whether to match P2P requests. 51 * 52 * When matching against an instance of WifiNetworkSpecifier, simply matching SSID or 53 * BSSID patterns would let apps know if a given WiFi network's (B)SSID matches a pattern 54 * by simply filing a NetworkCallback with that pattern. Also, apps asking for a match on 55 * (B)SSID are apps requesting a P2P network, which involves protection with UI shown by 56 * the system, and the WifiNetworkSpecifiers for these P2P networks should never match 57 * an Internet-providing network to avoid calling back these apps on a network that happens 58 * to match their requested pattern but has not been brought up for them. 59 */ 60 private final boolean mMatchLocalOnlySpecifiers; 61 WifiNetworkAgentSpecifier(@onNull WifiConfiguration wifiConfiguration, @WifiBand int band, boolean matchLocalOnlySpecifiers)62 public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration, 63 @WifiBand int band, boolean matchLocalOnlySpecifiers) { 64 checkNotNull(wifiConfiguration); 65 66 mWifiConfiguration = wifiConfiguration; 67 mBand = band; 68 mMatchLocalOnlySpecifiers = matchLocalOnlySpecifiers; 69 } 70 71 /** 72 * @hide 73 */ 74 public static final @android.annotation.NonNull Creator<WifiNetworkAgentSpecifier> CREATOR = 75 new Creator<WifiNetworkAgentSpecifier>() { 76 @Override 77 public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) { 78 WifiConfiguration wifiConfiguration = in.readParcelable(null); 79 int band = in.readInt(); 80 boolean matchLocalOnlySpecifiers = in.readBoolean(); 81 return new WifiNetworkAgentSpecifier(wifiConfiguration, band, 82 matchLocalOnlySpecifiers); 83 } 84 85 @Override 86 public WifiNetworkAgentSpecifier[] newArray(int size) { 87 return new WifiNetworkAgentSpecifier[size]; 88 } 89 }; 90 91 @Override describeContents()92 public int describeContents() { 93 return 0; 94 } 95 96 @Override writeToParcel(@onNull Parcel dest, int flags)97 public void writeToParcel(@NonNull Parcel dest, int flags) { 98 dest.writeParcelable(mWifiConfiguration, flags); 99 dest.writeInt(mBand); 100 dest.writeBoolean(mMatchLocalOnlySpecifiers); 101 } 102 103 @Override canBeSatisfiedBy(@ullable NetworkSpecifier other)104 public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { 105 if (this == other) { 106 return true; 107 } 108 // Any generic requests should be satisifed by a specific wifi network. 109 if (other == null || other instanceof MatchAllNetworkSpecifier) { 110 return true; 111 } 112 if (other instanceof WifiNetworkSpecifier) { 113 return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other); 114 } 115 return equals(other); 116 } 117 118 /** 119 * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the 120 * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link android.net.NetworkAgent}. 121 */ satisfiesNetworkSpecifier(@onNull WifiNetworkSpecifier ns)122 public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) { 123 // None of these should be null by construction. 124 // {@link WifiNetworkSpecifier.Builder} enforces non-null in {@link WifiNetworkSpecifier}. 125 // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}. 126 checkNotNull(ns); 127 checkNotNull(ns.ssidPatternMatcher); 128 checkNotNull(ns.bssidPatternMatcher); 129 checkNotNull(ns.wifiConfiguration.allowedKeyManagement); 130 checkNotNull(this.mWifiConfiguration.SSID); 131 checkNotNull(this.mWifiConfiguration.BSSID); 132 checkNotNull(this.mWifiConfiguration.allowedKeyManagement); 133 134 if (!mMatchLocalOnlySpecifiers) { 135 // Specifiers that match non-local-only networks only match against the band. 136 if (mBand == ScanResult.WIFI_BAND_5_GHZ_LOW) { 137 return ns.getBand() == ScanResult.WIFI_BAND_5_GHZ_LOW 138 || ns.getBand() == ScanResult.WIFI_BAND_5_GHZ; 139 } else if (mBand == ScanResult.WIFI_BAND_5_GHZ_HIGH) { 140 return ns.getBand() == ScanResult.WIFI_BAND_5_GHZ_HIGH 141 || ns.getBand() == ScanResult.WIFI_BAND_5_GHZ; 142 } else { 143 return ns.getBand() == mBand; 144 } 145 } 146 if (ns.getBand() != ScanResult.UNSPECIFIED && ns.getBand() != mBand) { 147 return false; 148 } 149 final String ssidWithQuotes = this.mWifiConfiguration.SSID; 150 checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\"")); 151 final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1); 152 if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) { 153 return false; 154 } 155 final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID); 156 final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first; 157 final MacAddress matchMask = ns.bssidPatternMatcher.second; 158 if (!bssid.matches(matchBaseAddress, matchMask)) { 159 return false; 160 } 161 if (!ns.wifiConfiguration.allowedKeyManagement.equals( 162 this.mWifiConfiguration.allowedKeyManagement)) { 163 return false; 164 } 165 return true; 166 } 167 168 @Override hashCode()169 public int hashCode() { 170 return Objects.hash( 171 mWifiConfiguration.SSID, 172 mWifiConfiguration.BSSID, 173 mWifiConfiguration.allowedKeyManagement, 174 mBand, 175 mMatchLocalOnlySpecifiers); 176 } 177 178 @Override equals(Object obj)179 public boolean equals(Object obj) { 180 if (this == obj) { 181 return true; 182 } 183 if (!(obj instanceof WifiNetworkAgentSpecifier)) { 184 return false; 185 } 186 WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj; 187 return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID) 188 && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID) 189 && Objects.equals(this.mWifiConfiguration.allowedKeyManagement, 190 lhs.mWifiConfiguration.allowedKeyManagement) 191 && mBand == lhs.mBand 192 && mMatchLocalOnlySpecifiers == lhs.mMatchLocalOnlySpecifiers; 193 } 194 195 @Override toString()196 public String toString() { 197 StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier ["); 198 sb.append("WifiConfiguration=") 199 .append(", SSID=").append(mWifiConfiguration.SSID) 200 .append(", BSSID=").append(mWifiConfiguration.BSSID) 201 .append(", band=").append(mBand) 202 .append(", mMatchLocalOnlySpecifiers=").append(mMatchLocalOnlySpecifiers) 203 .append("]"); 204 return sb.toString(); 205 } 206 207 @Override redact()208 public NetworkSpecifier redact() { 209 return null; 210 } 211 } 212