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