1 /*
2  * Copyright (C) 2010 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 com.android.server.wifi;
18 
19 import static android.net.util.KeepalivePacketDataUtil.parseTcpKeepalivePacketData;
20 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE;
21 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT;
22 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY;
23 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_UNWANTED_LOW_RSSI;
24 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256;
25 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384;
26 import static android.net.wifi.WifiManager.WIFI_FEATURE_LINK_LAYER_STATS;
27 import static android.net.wifi.WifiManager.WIFI_FEATURE_TDLS;
28 import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE;
29 
30 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
31 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
32 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
33 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
34 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
35 import static com.android.server.wifi.WifiSettingsConfigStore.SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS;
36 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS;
37 import static com.android.server.wifi.proto.WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__SUPPLICANT_DISCONNECTED;
38 
39 import android.annotation.IntDef;
40 import android.annotation.NonNull;
41 import android.annotation.Nullable;
42 import android.annotation.SuppressLint;
43 import android.app.ActivityManager;
44 import android.app.BroadcastOptions;
45 import android.app.admin.SecurityLog;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.net.CaptivePortalData;
49 import android.net.ConnectivityManager;
50 import android.net.DhcpResultsParcelable;
51 import android.net.InvalidPacketException;
52 import android.net.IpConfiguration;
53 import android.net.KeepalivePacketData;
54 import android.net.Layer2PacketParcelable;
55 import android.net.LinkProperties;
56 import android.net.MacAddress;
57 import android.net.NattKeepalivePacketData;
58 import android.net.Network;
59 import android.net.NetworkAgent;
60 import android.net.NetworkAgentConfig;
61 import android.net.NetworkCapabilities;
62 import android.net.NetworkInfo;
63 import android.net.NetworkInfo.DetailedState;
64 import android.net.RouteInfo;
65 import android.net.SocketKeepalive;
66 import android.net.StaticIpConfiguration;
67 import android.net.TcpKeepalivePacketData;
68 import android.net.TcpKeepalivePacketDataParcelable;
69 import android.net.Uri;
70 import android.net.ip.IIpClient;
71 import android.net.ip.IpClientCallbacks;
72 import android.net.ip.IpClientManager;
73 import android.net.networkstack.aidl.dhcp.DhcpOption;
74 import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable;
75 import android.net.networkstack.aidl.ip.ReachabilityLossReason;
76 import android.net.shared.Layer2Information;
77 import android.net.shared.ProvisioningConfiguration;
78 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
79 import android.net.vcn.VcnManager;
80 import android.net.vcn.VcnNetworkPolicyResult;
81 import android.net.wifi.IWifiConnectedNetworkScorer;
82 import android.net.wifi.MloLink;
83 import android.net.wifi.ScanResult;
84 import android.net.wifi.SecurityParams;
85 import android.net.wifi.SupplicantState;
86 import android.net.wifi.WifiAnnotations.WifiStandard;
87 import android.net.wifi.WifiConfiguration;
88 import android.net.wifi.WifiContext;
89 import android.net.wifi.WifiEnterpriseConfig;
90 import android.net.wifi.WifiInfo;
91 import android.net.wifi.WifiManager;
92 import android.net.wifi.WifiManager.DeviceMobilityState;
93 import android.net.wifi.WifiNetworkAgentSpecifier;
94 import android.net.wifi.WifiNetworkSpecifier;
95 import android.net.wifi.WifiSsid;
96 import android.net.wifi.flags.Flags;
97 import android.net.wifi.hotspot2.IProvisioningCallback;
98 import android.net.wifi.hotspot2.OsuProvider;
99 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
100 import android.net.wifi.util.ScanResultUtil;
101 import android.os.BatteryStatsManager;
102 import android.os.Build;
103 import android.os.Bundle;
104 import android.os.ConditionVariable;
105 import android.os.IBinder;
106 import android.os.Looper;
107 import android.os.Message;
108 import android.os.Messenger;
109 import android.os.PowerManager;
110 import android.os.Process;
111 import android.os.UserHandle;
112 import android.os.WorkSource;
113 import android.provider.Settings;
114 import android.system.OsConstants;
115 import android.telephony.SubscriptionManager;
116 import android.telephony.TelephonyManager;
117 import android.text.TextUtils;
118 import android.util.ArraySet;
119 import android.util.Log;
120 import android.util.Pair;
121 import android.util.Range;
122 
123 import androidx.annotation.RequiresApi;
124 
125 import com.android.internal.annotations.VisibleForTesting;
126 import com.android.internal.util.IState;
127 import com.android.internal.util.Protocol;
128 import com.android.internal.util.State;
129 import com.android.internal.util.StateMachine;
130 import com.android.modules.utils.HandlerExecutor;
131 import com.android.modules.utils.build.SdkLevel;
132 import com.android.net.module.util.Inet4AddressUtils;
133 import com.android.net.module.util.MacAddressUtils;
134 import com.android.net.module.util.NetUtils;
135 import com.android.server.wifi.ActiveModeManager.ClientRole;
136 import com.android.server.wifi.MboOceController.BtmFrameData;
137 import com.android.server.wifi.SupplicantStaIfaceHal.QosPolicyRequest;
138 import com.android.server.wifi.SupplicantStaIfaceHal.StaIfaceReasonCode;
139 import com.android.server.wifi.SupplicantStaIfaceHal.StaIfaceStatusCode;
140 import com.android.server.wifi.SupplicantStaIfaceHal.SupplicantEventCode;
141 import com.android.server.wifi.WifiCarrierInfoManager.SimAuthRequestData;
142 import com.android.server.wifi.WifiCarrierInfoManager.SimAuthResponseData;
143 import com.android.server.wifi.WifiNative.RxFateReport;
144 import com.android.server.wifi.WifiNative.TxFateReport;
145 import com.android.server.wifi.hotspot2.AnqpEvent;
146 import com.android.server.wifi.hotspot2.IconEvent;
147 import com.android.server.wifi.hotspot2.NetworkDetail;
148 import com.android.server.wifi.hotspot2.PasspointManager;
149 import com.android.server.wifi.hotspot2.WnmData;
150 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
151 import com.android.server.wifi.proto.WifiStatsLog;
152 import com.android.server.wifi.proto.nano.WifiMetricsProto;
153 import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent;
154 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent;
155 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats;
156 import com.android.server.wifi.util.ActionListenerWrapper;
157 import com.android.server.wifi.util.InformationElementUtil;
158 import com.android.server.wifi.util.NativeUtil;
159 import com.android.server.wifi.util.RssiUtil;
160 import com.android.server.wifi.util.StateMachineObituary;
161 import com.android.server.wifi.util.WifiPermissionsUtil;
162 import com.android.wifi.resources.R;
163 
164 import java.io.BufferedReader;
165 import java.io.FileDescriptor;
166 import java.io.FileNotFoundException;
167 import java.io.IOException;
168 import java.io.PrintWriter;
169 import java.lang.annotation.Retention;
170 import java.lang.annotation.RetentionPolicy;
171 import java.net.Inet4Address;
172 import java.net.Inet6Address;
173 import java.net.InetAddress;
174 import java.net.URL;
175 import java.time.Duration;
176 import java.util.ArrayList;
177 import java.util.Arrays;
178 import java.util.Collections;
179 import java.util.List;
180 import java.util.Map;
181 import java.util.Objects;
182 import java.util.Set;
183 import java.util.stream.Collectors;
184 
185 /**
186  * Implementation of ClientMode.  Event handling for Client mode logic is done here,
187  * and all changes in connectivity state are initiated here.
188  *
189  * Note: No external modules should be calling into {@link ClientModeImpl}. Please plumb it via
190  * {@link ClientModeManager} until b/160014176 is fixed.
191  */
192 public class ClientModeImpl extends StateMachine implements ClientMode {
193     private static final String NETWORKTYPE = "WIFI";
194     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE_LOW_MEMORY = 200;
195     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE = 3000;
196 
197     private static final String TAG = "WifiClientModeImpl";
198     // Hardcoded constant used for caller to avoid triggering connect choice that force framework
199     // to stick to the selected network. Do not change this value to maintain backward
200     // compatibility.
201     public static final String ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE =
202             "ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE";
203 
204     private static final int IPCLIENT_STARTUP_TIMEOUT_MS = 2_000;
205     private static final int IPCLIENT_SHUTDOWN_TIMEOUT_MS = 60_000; // 60 seconds
206     private static final int NETWORK_AGENT_TEARDOWN_DELAY_MS = 5_000; // Max teardown delay.
207     private static final int DISASSOC_AP_BUSY_DISABLE_DURATION_MS = 5 * 60 * 1000; // 5 minutes
208     @VisibleForTesting public static final long CONNECTING_WATCHDOG_TIMEOUT_MS = 30_000; // 30 secs.
209     public static final int PROVISIONING_TIMEOUT_FILS_CONNECTION_MS = 36_000; // 36 secs.
210     @VisibleForTesting
211     public static final String ARP_TABLE_PATH = "/proc/net/arp";
212     private final WifiDeviceStateChangeManager mWifiDeviceStateChangeManager;
213 
214     private boolean mVerboseLoggingEnabled = false;
215 
216     /**
217      * Log with error attribute
218      *
219      * @param s is string log
220      */
221     @Override
loge(String s)222     protected void loge(String s) {
223         Log.e(getTag(), s, null);
224     }
225     @Override
logd(String s)226     protected void logd(String s) {
227         Log.d(getTag(), s, null);
228     }
229     @Override
log(String s)230     protected void log(String s) {
231         Log.d(getTag(), s, null);
232     }
233     private final WifiContext mContext;
234     private final WifiMetrics mWifiMetrics;
235     private final WifiMonitor mWifiMonitor;
236     private final WifiNative mWifiNative;
237     private final WifiPermissionsUtil mWifiPermissionsUtil;
238     private final WifiConfigManager mWifiConfigManager;
239     private final WifiConnectivityManager mWifiConnectivityManager;
240     private final WifiBlocklistMonitor mWifiBlocklistMonitor;
241     private final WifiDiagnostics mWifiDiagnostics;
242     private final Clock mClock;
243     private final WifiScoreCard mWifiScoreCard;
244     private final WifiHealthMonitor mWifiHealthMonitor;
245     private final WifiScoreReport mWifiScoreReport;
246     private final WifiTrafficPoller mWifiTrafficPoller;
247     private final PasspointManager mPasspointManager;
248     private final WifiDataStall mWifiDataStall;
249     private final RssiMonitor mRssiMonitor;
250     private final MboOceController mMboOceController;
251     private final McastLockManagerFilterController mMcastLockManagerFilterController;
252     private final ActivityManager mActivityManager;
253     private final FrameworkFacade mFacade;
254     private final WifiStateTracker mWifiStateTracker;
255     private final WrongPasswordNotifier mWrongPasswordNotifier;
256     private final EapFailureNotifier mEapFailureNotifier;
257     private final SimRequiredNotifier mSimRequiredNotifier;
258     private final ConnectionFailureNotifier mConnectionFailureNotifier;
259     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
260     private final ThroughputPredictor mThroughputPredictor;
261     private final DeviceConfigFacade mDeviceConfigFacade;
262     private final ScoringParams mScoringParams;
263     private final WifiThreadRunner mWifiThreadRunner;
264     private final ScanRequestProxy mScanRequestProxy;
265     private final WifiLastResortWatchdog mWifiLastResortWatchdog;
266     private final WakeupController mWakeupController;
267     private final WifiLockManager mWifiLockManager;
268     private final WifiP2pConnection mWifiP2pConnection;
269     private final WifiGlobals mWifiGlobals;
270     private final ClientModeManagerBroadcastQueue mBroadcastQueue;
271     private final TelephonyManager mTelephonyManager;
272     private final WifiSettingsConfigStore mSettingsConfigStore;
273     private final long mId;
274 
275     private boolean mScreenOn = false;
276 
277     private final String mInterfaceName;
278     private final ConcreteClientModeManager mClientModeManager;
279 
280     private final WifiNotificationManager mNotificationManager;
281     private final WifiConnectivityHelper mWifiConnectivityHelper;
282     private final QosPolicyRequestHandler mQosPolicyRequestHandler;
283 
284     private boolean mFailedToResetMacAddress = false;
285     private int mLastSignalLevel = -1;
286     private int mLastTxKbps = -1;
287     private int mLastRxKbps = -1;
288     private int mLastScanRssi = WifiInfo.INVALID_RSSI;
289     private String mLastBssid;
290     // TODO (b/162942761): Ensure this is reset when mTargetNetworkId is set.
291     private int mLastNetworkId; // The network Id we successfully joined
292     // The subId used by WifiConfiguration with SIM credential which was connected successfully
293     private int mLastSubId;
294     private String mLastSimBasedConnectionCarrierName;
295     private URL mTermsAndConditionsUrl; // Indicates that the Passpoint network is captive
296     @Nullable
297     private WifiNative.ConnectionCapabilities mLastConnectionCapabilities;
298     private int mPowerSaveDisableRequests = 0; // mask based on @PowerSaveClientType
299     private boolean mIsUserSelected = false;
300     private boolean mCurrentConnectionDetectedCaptivePortal;
301     // Overrides StatsLog disconnect reason logging for NETWORK_DISCONNECTION_EVENT with specific
302     // framework initiated disconnect reason code.
303     private int mFrameworkDisconnectReasonOverride;
304 
305     private boolean mIpProvisioningTimedOut = false;
306 
getTag()307     private String getTag() {
308         return TAG + "[" + mId + ":" + (mInterfaceName == null ? "unknown" : mInterfaceName) + "]";
309     }
310 
311     private boolean mEnableRssiPolling = false;
312     private int mRssiPollToken = 0;
313 
314     private PowerManager.WakeLock mSuspendWakeLock;
315 
316     /**
317      * Value to set in wpa_supplicant "bssid" field when we don't want to restrict connection to
318      * a specific AP.
319      */
320     public static final String SUPPLICANT_BSSID_ANY = "any";
321 
322     /**
323      * The link properties of the wifi interface.
324      * Do not modify this directly; use updateLinkProperties instead.
325      */
326     private LinkProperties mLinkProperties;
327 
328     private final Object mDhcpResultsParcelableLock = new Object();
329     @NonNull
330     private DhcpResultsParcelable mDhcpResultsParcelable = new DhcpResultsParcelable();
331 
332     // NOTE: Do not return to clients - see getConnectionInfo()
333     private final ExtendedWifiInfo mWifiInfo;
334     // TODO : remove this member. It should be possible to only call sendNetworkChangeBroadcast when
335     // the state actually changed, and to deduce the state of the agent from the state of the
336     // machine when generating the NetworkInfo for the broadcast.
337     private DetailedState mNetworkAgentState;
338     private final SupplicantStateTracker mSupplicantStateTracker;
339 
340     // Indicates that framework is attempting to roam, set true on CMD_START_ROAM, set false when
341     // wifi connects or fails to connect
342     private boolean mIsAutoRoaming = false;
343 
344     // Indicates that driver is attempting to allowlist roaming, set true on allowlist roam BSSID
345     // associated, set false when wifi connects or fails to connect
346     private boolean mIsLinkedNetworkRoaming = false;
347 
348     // Roaming failure count
349     private int mRoamFailCount = 0;
350 
351     // This is the BSSID we are trying to associate to, it can be set to SUPPLICANT_BSSID_ANY
352     // if we havent selected a BSSID for joining.
353     private String mTargetBssid = SUPPLICANT_BSSID_ANY;
354     private int mTargetBand = ScanResult.UNSPECIFIED;
355     // This one is used to track the current target network ID. This is used for error
356     // handling during connection setup since many error message from supplicant does not report
357     // SSID. Once connected, it will be set to invalid
358     // TODO (b/162942761): Ensure this is reset when mLastNetworkId is set.
359     private int mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
360     private WifiConfiguration mTargetWifiConfiguration = null;
361     @Nullable private VcnManager mVcnManager = null;
362 
363     // This is is used to track the number of TDLS peers enabled in driver via enableTdls()
364     private Set<String> mEnabledTdlsPeers = new ArraySet<>();
365 
366     // Tracks the last NUD failure timestamp, and number of failures.
367     private Pair<Long, Integer> mNudFailureCounter = new Pair<>(0L, 0);
368 
369     /**
370      * Method to clear {@link #mTargetBssid} and reset the current connected network's
371      * bssid in wpa_supplicant after a roam/connect attempt.
372      */
clearTargetBssid(String dbg)373     public boolean clearTargetBssid(String dbg) {
374         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
375         if (config == null) {
376             return false;
377         }
378         String bssid = SUPPLICANT_BSSID_ANY;
379         if (config.BSSID != null) {
380             bssid = config.BSSID;
381             if (mVerboseLoggingEnabled) {
382                 Log.d(getTag(), "force BSSID to " + bssid + "due to config");
383             }
384         }
385         if (mVerboseLoggingEnabled) {
386             logd(dbg + " clearTargetBssid " + bssid + " key=" + config.getProfileKey());
387         }
388         mTargetBssid = bssid;
389         return mWifiNative.setNetworkBSSID(mInterfaceName, bssid);
390     }
391 
392     /**
393      * Set Config's default BSSID (for association purpose) and {@link #mTargetBssid}
394      * @param config config need set BSSID
395      * @param bssid  default BSSID to assocaite with when connect to this network
396      * @return false -- does not change the current default BSSID of the configure
397      *         true -- change the  current default BSSID of the configur
398      */
setTargetBssid(WifiConfiguration config, String bssid)399     private boolean setTargetBssid(WifiConfiguration config, String bssid) {
400         if (config == null || bssid == null) {
401             return false;
402         }
403         if (config.BSSID != null) {
404             bssid = config.BSSID;
405             if (mVerboseLoggingEnabled) {
406                 Log.d(getTag(), "force BSSID to " + bssid + "due to config");
407             }
408         }
409         if (mVerboseLoggingEnabled) {
410             Log.d(getTag(), "setTargetBssid set to " + bssid + " key="
411                     + config.getProfileKey());
412         }
413         mTargetBssid = bssid;
414         config.getNetworkSelectionStatus().setNetworkSelectionBSSID(bssid);
415         return true;
416     }
417 
418     private volatile IpClientManager mIpClient;
419     private IpClientCallbacksImpl mIpClientCallbacks;
420     private static int sIpClientCallbacksIndex = 0;
421 
422     private final WifiNetworkFactory mNetworkFactory;
423     private final UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
424     private final OemWifiNetworkFactory mOemWifiNetworkFactory;
425     private final RestrictedWifiNetworkFactory mRestrictedWifiNetworkFactory;
426     @VisibleForTesting
427     InsecureEapNetworkHandler mInsecureEapNetworkHandler;
428     boolean mLeafCertSent;
429     @VisibleForTesting
430     InsecureEapNetworkHandler.InsecureEapNetworkHandlerCallbacks
431             mInsecureEapNetworkHandlerCallbacksImpl;
432     private final MultiInternetManager mMultiInternetManager;
433 
434     @VisibleForTesting
435     @Nullable
436     WifiNetworkAgent mNetworkAgent;
437 
438 
439     // Used to filter out requests we couldn't possibly satisfy.
440     private final NetworkCapabilities mNetworkCapabilitiesFilter;
441 
442     /* The base for wifi message types */
443     static final int BASE = Protocol.BASE_WIFI;
444 
445     /* BT connection state changed, e.g., connected/disconnected */
446     static final int CMD_BLUETOOTH_CONNECTION_STATE_CHANGE              = BASE + 31;
447 
448     /* Supplicant commands after driver start*/
449     /* Disconnect from a network */
450     static final int CMD_DISCONNECT                                     = BASE + 73;
451     /* Reconnect to a network */
452     static final int CMD_RECONNECT                                      = BASE + 74;
453     /* Reassociate to a network */
454     static final int CMD_REASSOCIATE                                    = BASE + 75;
455 
456     /* Enables RSSI poll */
457     static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
458     /* RSSI poll */
459     static final int CMD_RSSI_POLL                                      = BASE + 83;
460     /** Runs RSSI poll once */
461     static final int CMD_ONESHOT_RSSI_POLL                              = BASE + 84;
462     /* Enable suspend mode optimizations in the driver */
463     static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
464     /* L3 provisioning timed out*/
465     static final int CMD_IP_PROVISIONING_TIMEOUT                        = BASE + 87;
466 
467 
468     /**
469      * Watchdog for protecting against b/16823537
470      * Leave time for 4-way handshake to succeed
471      */
472     static final int ROAM_GUARD_TIMER_MSEC = 15000;
473 
474     int mRoamWatchdogCount = 0;
475     /* Roam state watchdog */
476     static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
477     /* Screen change intent handling */
478     static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
479 
480     /* Disconnecting state watchdog */
481     static final int CMD_CONNECTING_WATCHDOG_TIMER                      = BASE + 96;
482 
483     /* SIM is removed; reset any cached data for it */
484     static final int CMD_RESET_SIM_NETWORKS                             = BASE + 101;
485 
486     /**
487      * Update the OOB Pseudonym which is retrieved from the carrier's entitlement server for
488      * EAP-SIM/AKA/AKA' into supplicant.
489      */
490     static final int CMD_UPDATE_OOB_PSEUDONYM                               = BASE + 102;
491 
492     @Retention(RetentionPolicy.SOURCE)
493     @IntDef(prefix = {"RESET_SIM_REASON_"},
494             value = {
495                     RESET_SIM_REASON_SIM_REMOVED,
496                     RESET_SIM_REASON_SIM_INSERTED,
497                     RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED})
498     @interface ResetSimReason {}
499     static final int RESET_SIM_REASON_SIM_REMOVED              = 0;
500     static final int RESET_SIM_REASON_SIM_INSERTED             = 1;
501     static final int RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED = 2;
502 
503     /** Connecting watchdog timeout counter */
504     private int mConnectingWatchdogCount = 0;
505 
506     /* We now have a valid IP configuration. */
507     static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
508     /* We no longer have a valid IP configuration. */
509     static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
510     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
511     static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
512 
513     static final int CMD_START_CONNECT                                  = BASE + 143;
514 
515     @VisibleForTesting
516     public static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
517     private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
518     @VisibleForTesting
519     public static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
520 
521     static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
522 
523     static final int CMD_START_ROAM                                     = BASE + 145;
524 
525     static final int CMD_NETWORK_STATUS                                 = BASE + 148;
526 
527     /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
528     static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
529 
530     static final int CMD_IP_REACHABILITY_FAILURE                        = BASE + 150;
531 
532     static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
533 
534     /* used to offload sending IP packet */
535     static final int CMD_START_IP_PACKET_OFFLOAD                        = BASE + 160;
536 
537     /* used to stop offload sending IP packet */
538     static final int CMD_STOP_IP_PACKET_OFFLOAD                         = BASE + 161;
539 
540     /* Used to time out the creation of an IpClient instance. */
541     static final int CMD_IPCLIENT_STARTUP_TIMEOUT                       = BASE + 165;
542 
543     /**
544      * Used to handle messages bounced between ClientModeImpl and IpClient.
545      */
546     static final int CMD_IPV4_PROVISIONING_SUCCESS                      = BASE + 200;
547     static final int CMD_IPV4_PROVISIONING_FAILURE                      = BASE + 201;
548 
549     /* Push a new APF program to the HAL */
550     static final int CMD_INSTALL_PACKET_FILTER                          = BASE + 202;
551 
552     /* Enable/disable fallback packet filtering */
553     static final int CMD_SET_FALLBACK_PACKET_FILTERING                  = BASE + 203;
554 
555     /* Enable/disable Neighbor Discovery offload functionality. */
556     static final int CMD_CONFIG_ND_OFFLOAD                              = BASE + 204;
557 
558     /* Read the APF program & data buffer */
559     static final int CMD_READ_PACKET_FILTER                             = BASE + 208;
560 
561     /** Used to add packet filter to apf. */
562     static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = BASE + 209;
563 
564     /** Used to remove packet filter from apf. */
565     static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = BASE + 210;
566 
567     /**
568      * Set maximum acceptable DTIM multiplier to hardware driver. Any multiplier larger than the
569      * maximum value must not be accepted, it will cause packet loss higher than what the system
570      * can accept, which will cause unexpected behavior for apps, and may interrupt the network
571      * connection.
572      */
573     static final int CMD_SET_MAX_DTIM_MULTIPLIER = BASE + 211;
574 
575     @VisibleForTesting
576     static final int CMD_PRE_DHCP_ACTION                                = BASE + 255;
577     @VisibleForTesting
578     static final int CMD_PRE_DHCP_ACTION_COMPLETE                       = BASE + 256;
579     private static final int CMD_POST_DHCP_ACTION                       = BASE + 257;
580 
581     private static final int CMD_CONNECT_NETWORK                        = BASE + 258;
582     private static final int CMD_SAVE_NETWORK                           = BASE + 259;
583 
584     /* Start connection to FILS AP*/
585     static final int CMD_START_FILS_CONNECTION                          = BASE + 262;
586 
587     static final int CMD_IPCLIENT_CREATED                               = BASE + 300;
588 
589     @VisibleForTesting
590     static final int CMD_ACCEPT_EAP_SERVER_CERTIFICATE                  = BASE + 301;
591 
592     @VisibleForTesting
593     static final int CMD_REJECT_EAP_INSECURE_CONNECTION                 = BASE + 302;
594 
595     /* Tracks if suspend optimizations need to be disabled by DHCP,
596      * screen or due to high perf mode.
597      * When any of them needs to disable it, we keep the suspend optimizations
598      * disabled
599      */
600     private int mSuspendOptNeedsDisabled = 0;
601 
602     private static final int SUSPEND_DUE_TO_DHCP = 1;
603     private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
604     private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
605 
606     /* Timeout after which a network connection stuck in L3 provisioning is considered as local
607     only. It should be at least equal to ProvisioningConfiguration#DEFAULT_TIMEOUT_MS */
608     @VisibleForTesting
609     public static final long WAIT_FOR_L3_PROVISIONING_TIMEOUT_MS = 18000;
610 
611     /** @see #isRecentlySelectedByTheUser */
612     @VisibleForTesting
613     public static final int LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS = 30 * 1000;
614 
615     /* Tracks if user has enabled Connected Mac Randomization through settings */
616 
617     int mRunningBeaconCount = 0;
618 
619     /* Parent state where connections are allowed */
620     private State mConnectableState;
621     /* Connecting/Connected to an access point */
622     private State mConnectingOrConnectedState;
623     /* Connecting to an access point */
624     private State mL2ConnectingState;
625     /* Connected at 802.11 (L2) level */
626     private State mL2ConnectedState;
627     /* Waiting for IpClient recreation completes */
628     private State mWaitBeforeL3ProvisioningState;
629     /* fetching IP after connection to access point (assoc+auth complete) */
630     private State mL3ProvisioningState;
631     /* Connected with IP addr */
632     private State mL3ConnectedState;
633     /* Roaming */
634     private State mRoamingState;
635     /* Network is not connected, supplicant assoc+auth is not complete */
636     private State mDisconnectedState;
637 
638     /*
639      * FILS connection related variables.
640      */
641     /* To indicate to IpClient whether HLP IEs were included or not in assoc request */
642     private boolean mSentHLPs = false;
643     /* Tracks IpClient start state until (FILS_)NETWORK_CONNECTION_EVENT event */
644     private boolean mIpClientWithPreConnection = false;
645 
646     /**
647      * Work source to use to blame usage on the WiFi service
648      */
649     public static final WorkSource WIFI_WORK_SOURCE = new WorkSource(Process.WIFI_UID);
650 
651     private final BatteryStatsManager mBatteryStatsManager;
652 
653     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
654 
655     private final WifiPseudonymManager mWifiPseudonymManager;
656 
657     private final OnNetworkUpdateListener mOnNetworkUpdateListener;
658 
659     private final OnCarrierOffloadDisabledListener mOnCarrierOffloadDisabledListener;
660 
661     private final ClientModeImplMonitor mCmiMonitor;
662 
663     private final WifiNetworkSelector mWifiNetworkSelector;
664 
665     private final WifiInjector mWifiInjector;
666 
667     // Permanently disable a network due to no internet if the estimated probability of having
668     // internet is less than this value.
669     @VisibleForTesting
670     public static final int PROBABILITY_WITH_INTERNET_TO_PERMANENTLY_DISABLE_NETWORK = 60;
671     // Disable a network permanently due to wrong password even if the network had successfully
672     // connected before wrong password failure on this network reached this threshold.
673     public static final int THRESHOLD_TO_PERM_WRONG_PASSWORD = 3;
674 
675     // Maximum duration to continue to log Wifi usability stats after a data stall is triggered.
676     @VisibleForTesting
677     public static final long DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS = 30 * 1000;
678     private long mDataStallTriggerTimeMs = -1;
679     private int mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
680 
681     @Nullable
682     private StateMachineObituary mObituary = null;
683 
684     @Nullable
685     private WifiVcnNetworkPolicyChangeListener mVcnPolicyChangeListener;
686 
687     /** NETWORK_NOT_FOUND_EVENT event counter */
688     private int mNetworkNotFoundEventCount = 0;
689 
690     private final WifiPseudonymManager.PseudonymUpdatingListener mPseudonymUpdatingListener;
691 
692     private final ApplicationQosPolicyRequestHandler mApplicationQosPolicyRequestHandler;
693 
694     @VisibleForTesting
695     public static final String X509_CERTIFICATE_EXPIRED_ERROR_STRING = "certificate has expired";
696     @VisibleForTesting
697     public static final int EAP_FAILURE_CODE_CERTIFICATE_EXPIRED = 32768;
698     private boolean mCurrentConnectionReportedCertificateExpired = false;
699 
700 
701     /** Note that this constructor will also start() the StateMachine. */
ClientModeImpl( @onNull WifiContext context, @NonNull WifiMetrics wifiMetrics, @NonNull Clock clock, @NonNull WifiScoreCard wifiScoreCard, @NonNull WifiStateTracker wifiStateTracker, @NonNull WifiPermissionsUtil wifiPermissionsUtil, @NonNull WifiConfigManager wifiConfigManager, @NonNull PasspointManager passpointManager, @NonNull WifiMonitor wifiMonitor, @NonNull WifiDiagnostics wifiDiagnostics, @NonNull WifiDataStall wifiDataStall, @NonNull ScoringParams scoringParams, @NonNull WifiThreadRunner wifiThreadRunner, @NonNull WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager, @NonNull WifiHealthMonitor wifiHealthMonitor, @NonNull ThroughputPredictor throughputPredictor, @NonNull DeviceConfigFacade deviceConfigFacade, @NonNull ScanRequestProxy scanRequestProxy, @NonNull ExtendedWifiInfo wifiInfo, @NonNull WifiConnectivityManager wifiConnectivityManager, @NonNull WifiBlocklistMonitor wifiBlocklistMonitor, @NonNull ConnectionFailureNotifier connectionFailureNotifier, @NonNull NetworkCapabilities networkCapabilitiesFilter, @NonNull WifiNetworkFactory networkFactory, @NonNull UntrustedWifiNetworkFactory untrustedWifiNetworkFactory, @NonNull OemWifiNetworkFactory oemPaidWifiNetworkFactory, @NonNull RestrictedWifiNetworkFactory restrictedWifiNetworkFactory, @NonNull MultiInternetManager multiInternetManager, @NonNull WifiLastResortWatchdog wifiLastResortWatchdog, @NonNull WakeupController wakeupController, @NonNull WifiLockManager wifiLockManager, @NonNull FrameworkFacade facade, @NonNull Looper looper, @NonNull WifiNative wifiNative, @NonNull WrongPasswordNotifier wrongPasswordNotifier, @NonNull WifiTrafficPoller wifiTrafficPoller, long id, @NonNull BatteryStatsManager batteryStatsManager, @NonNull SupplicantStateTracker supplicantStateTracker, @NonNull MboOceController mboOceController, @NonNull WifiCarrierInfoManager wifiCarrierInfoManager, @NonNull WifiPseudonymManager wifiPseudonymManager, @NonNull EapFailureNotifier eapFailureNotifier, @NonNull SimRequiredNotifier simRequiredNotifier, @NonNull WifiScoreReport wifiScoreReport, @NonNull WifiP2pConnection wifiP2pConnection, @NonNull WifiGlobals wifiGlobals, @NonNull String ifaceName, @NonNull ConcreteClientModeManager clientModeManager, @NonNull ClientModeImplMonitor cmiMonitor, @NonNull ClientModeManagerBroadcastQueue broadcastQueue, @NonNull WifiNetworkSelector wifiNetworkSelector, @NonNull TelephonyManager telephonyManager, @NonNull WifiInjector wifiInjector, @NonNull WifiSettingsConfigStore settingsConfigStore, boolean verboseLoggingEnabled, @NonNull WifiNotificationManager wifiNotificationManager, @NonNull WifiConnectivityHelper wifiConnectivityHelper)702     public ClientModeImpl(
703             @NonNull WifiContext context,
704             @NonNull WifiMetrics wifiMetrics,
705             @NonNull Clock clock,
706             @NonNull WifiScoreCard wifiScoreCard,
707             @NonNull WifiStateTracker wifiStateTracker,
708             @NonNull WifiPermissionsUtil wifiPermissionsUtil,
709             @NonNull WifiConfigManager wifiConfigManager,
710             @NonNull PasspointManager passpointManager,
711             @NonNull WifiMonitor wifiMonitor,
712             @NonNull WifiDiagnostics wifiDiagnostics,
713             @NonNull WifiDataStall wifiDataStall,
714             @NonNull ScoringParams scoringParams,
715             @NonNull WifiThreadRunner wifiThreadRunner,
716             @NonNull WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager,
717             @NonNull WifiHealthMonitor wifiHealthMonitor,
718             @NonNull ThroughputPredictor throughputPredictor,
719             @NonNull DeviceConfigFacade deviceConfigFacade,
720             @NonNull ScanRequestProxy scanRequestProxy,
721             @NonNull ExtendedWifiInfo wifiInfo,
722             @NonNull WifiConnectivityManager wifiConnectivityManager,
723             @NonNull WifiBlocklistMonitor wifiBlocklistMonitor,
724             @NonNull ConnectionFailureNotifier connectionFailureNotifier,
725             @NonNull NetworkCapabilities networkCapabilitiesFilter,
726             @NonNull WifiNetworkFactory networkFactory,
727             @NonNull UntrustedWifiNetworkFactory untrustedWifiNetworkFactory,
728             @NonNull OemWifiNetworkFactory oemPaidWifiNetworkFactory,
729             @NonNull RestrictedWifiNetworkFactory restrictedWifiNetworkFactory,
730             @NonNull MultiInternetManager multiInternetManager,
731             @NonNull WifiLastResortWatchdog wifiLastResortWatchdog,
732             @NonNull WakeupController wakeupController,
733             @NonNull WifiLockManager wifiLockManager,
734             @NonNull FrameworkFacade facade,
735             @NonNull Looper looper,
736             @NonNull WifiNative wifiNative,
737             @NonNull WrongPasswordNotifier wrongPasswordNotifier,
738             @NonNull WifiTrafficPoller wifiTrafficPoller,
739             long id,
740             @NonNull BatteryStatsManager batteryStatsManager,
741             @NonNull SupplicantStateTracker supplicantStateTracker,
742             @NonNull MboOceController mboOceController,
743             @NonNull WifiCarrierInfoManager wifiCarrierInfoManager,
744             @NonNull WifiPseudonymManager wifiPseudonymManager,
745             @NonNull EapFailureNotifier eapFailureNotifier,
746             @NonNull SimRequiredNotifier simRequiredNotifier,
747             @NonNull WifiScoreReport wifiScoreReport,
748             @NonNull WifiP2pConnection wifiP2pConnection,
749             @NonNull WifiGlobals wifiGlobals,
750             @NonNull String ifaceName,
751             @NonNull ConcreteClientModeManager clientModeManager,
752             @NonNull ClientModeImplMonitor cmiMonitor,
753             @NonNull ClientModeManagerBroadcastQueue broadcastQueue,
754             @NonNull WifiNetworkSelector wifiNetworkSelector,
755             @NonNull TelephonyManager telephonyManager,
756             @NonNull WifiInjector wifiInjector,
757             @NonNull WifiSettingsConfigStore settingsConfigStore,
758             boolean verboseLoggingEnabled,
759             @NonNull WifiNotificationManager wifiNotificationManager,
760             @NonNull WifiConnectivityHelper wifiConnectivityHelper) {
761         super(TAG, looper);
762         mWifiMetrics = wifiMetrics;
763         mClock = clock;
764         mWifiScoreCard = wifiScoreCard;
765         mContext = context;
766         mFacade = facade;
767         mWifiNative = wifiNative;
768         mWrongPasswordNotifier = wrongPasswordNotifier;
769         mId = id;
770         mEapFailureNotifier = eapFailureNotifier;
771         mSimRequiredNotifier = simRequiredNotifier;
772         mWifiTrafficPoller = wifiTrafficPoller;
773         mMboOceController = mboOceController;
774         mWifiCarrierInfoManager = wifiCarrierInfoManager;
775         mWifiPseudonymManager = wifiPseudonymManager;
776         mBroadcastQueue = broadcastQueue;
777         mNetworkAgentState = DetailedState.DISCONNECTED;
778 
779         mBatteryStatsManager = batteryStatsManager;
780         mWifiStateTracker = wifiStateTracker;
781 
782         mWifiPermissionsUtil = wifiPermissionsUtil;
783         mWifiConfigManager = wifiConfigManager;
784 
785         mPasspointManager = passpointManager;
786 
787         mWifiMonitor = wifiMonitor;
788         mWifiDiagnostics = wifiDiagnostics;
789         mWifiDataStall = wifiDataStall;
790         mThroughputPredictor = throughputPredictor;
791         mDeviceConfigFacade = deviceConfigFacade;
792 
793         mWifiInfo = wifiInfo;
794         mSupplicantStateTracker = supplicantStateTracker;
795         mWifiConnectivityManager = wifiConnectivityManager;
796         mWifiBlocklistMonitor = wifiBlocklistMonitor;
797         mConnectionFailureNotifier = connectionFailureNotifier;
798 
799         mLinkProperties = new LinkProperties();
800         mMcastLockManagerFilterController = new McastLockManagerFilterController();
801         mActivityManager = context.getSystemService(ActivityManager.class);
802 
803         mLastBssid = null;
804         mIpProvisioningTimedOut = false;
805         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
806         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
807         mLastSimBasedConnectionCarrierName = null;
808         mLastSignalLevel = -1;
809 
810         mScoringParams = scoringParams;
811         mWifiThreadRunner = wifiThreadRunner;
812         mScanRequestProxy = scanRequestProxy;
813         mWifiScoreReport = wifiScoreReport;
814 
815         mNetworkCapabilitiesFilter = networkCapabilitiesFilter;
816         mNetworkFactory = networkFactory;
817 
818         mUntrustedNetworkFactory = untrustedWifiNetworkFactory;
819         mOemWifiNetworkFactory = oemPaidWifiNetworkFactory;
820         mRestrictedWifiNetworkFactory = restrictedWifiNetworkFactory;
821         mMultiInternetManager = multiInternetManager;
822 
823         mWifiLastResortWatchdog = wifiLastResortWatchdog;
824         mWakeupController = wakeupController;
825         mWifiLockManager = wifiLockManager;
826 
827         mWifiNetworkSuggestionsManager = wifiNetworkSuggestionsManager;
828         mWifiHealthMonitor = wifiHealthMonitor;
829         mWifiP2pConnection = wifiP2pConnection;
830         mWifiGlobals = wifiGlobals;
831 
832         mInterfaceName = ifaceName;
833         mClientModeManager = clientModeManager;
834         mCmiMonitor = cmiMonitor;
835         mTelephonyManager = telephonyManager;
836         mSettingsConfigStore = settingsConfigStore;
837         updateInterfaceCapabilities();
838         mWifiDeviceStateChangeManager = wifiInjector.getWifiDeviceStateChangeManager();
839 
840         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
841 
842         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
843         mSuspendWakeLock.setReferenceCounted(false);
844 
845         mOnNetworkUpdateListener = new OnNetworkUpdateListener();
846         mWifiConfigManager.addOnNetworkUpdateListener(mOnNetworkUpdateListener);
847 
848         mOnCarrierOffloadDisabledListener = new OnCarrierOffloadDisabledListener();
849         mWifiCarrierInfoManager.addOnCarrierOffloadDisabledListener(
850                 mOnCarrierOffloadDisabledListener);
851 
852         mWifiNetworkSelector = wifiNetworkSelector;
853         mWifiInjector = wifiInjector;
854         mQosPolicyRequestHandler = new QosPolicyRequestHandler(mInterfaceName, mWifiNative, this,
855                 mWifiInjector.getWifiHandlerThread());
856 
857         mRssiMonitor = new RssiMonitor(mWifiGlobals, mWifiThreadRunner, mWifiInfo, mWifiNative,
858                 mInterfaceName,
859                 () -> {
860                     updateCapabilities();
861                     updateCurrentConnectionInfo();
862                 },
863                 mDeviceConfigFacade);
864 
865         enableVerboseLogging(verboseLoggingEnabled);
866 
867         mNotificationManager = wifiNotificationManager;
868         mWifiConnectivityHelper = wifiConnectivityHelper;
869         mInsecureEapNetworkHandlerCallbacksImpl =
870                 new InsecureEapNetworkHandler.InsecureEapNetworkHandlerCallbacks() {
871                 @Override
872                 public void onAccept(String ssid, int networkId) {
873                     log("Accept Root CA cert for " + ssid);
874                     sendMessage(CMD_ACCEPT_EAP_SERVER_CERTIFICATE, networkId);
875                 }
876 
877                 @Override
878                 public void onReject(String ssid, boolean disconnectRequired) {
879                     log("Reject Root CA cert for " + ssid);
880                     sendMessage(CMD_REJECT_EAP_INSECURE_CONNECTION,
881                             WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_REJECTED_BY_USER,
882                             disconnectRequired ? 1 : 0, ssid);
883                 }
884 
885                 @Override
886                 public void onError(String ssid) {
887                     log("Insecure EAP network error for " + ssid);
888                     sendMessage(CMD_REJECT_EAP_INSECURE_CONNECTION,
889                             WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE,
890                             0, ssid);
891                 }};
892         mInsecureEapNetworkHandler = new InsecureEapNetworkHandler(
893                 mContext,
894                 mWifiConfigManager,
895                 mWifiNative,
896                 mFacade,
897                 mNotificationManager,
898                 mWifiInjector.getWifiDialogManager(),
899                 isTrustOnFirstUseSupported(),
900                 mWifiGlobals.isInsecureEnterpriseConfigurationAllowed(),
901                 mInsecureEapNetworkHandlerCallbacksImpl,
902                 mInterfaceName,
903                 getHandler());
904 
905         mPseudonymUpdatingListener = this::updatePseudonymFromOob;
906         mApplicationQosPolicyRequestHandler = mWifiInjector.getApplicationQosPolicyRequestHandler();
907 
908         final int threshold =  mContext.getResources().getInteger(
909                 R.integer.config_wifiConfigurationWifiRunnerThresholdInMs);
910         mConnectableState = new ConnectableState(threshold);
911         mConnectingOrConnectedState = new ConnectingOrConnectedState(threshold);
912         mL2ConnectingState = new L2ConnectingState(threshold);
913         mL2ConnectedState = new L2ConnectedState(threshold);
914         mWaitBeforeL3ProvisioningState = new WaitBeforeL3ProvisioningState(threshold);
915         mL3ProvisioningState = new L3ProvisioningState(threshold);
916         mL3ConnectedState = new L3ConnectedState(threshold);
917         mRoamingState = new RoamingState(threshold);
918         mDisconnectedState = new DisconnectedState(threshold);
919 
920         addState(mConnectableState); {
921             addState(mConnectingOrConnectedState, mConnectableState); {
922                 addState(mL2ConnectingState, mConnectingOrConnectedState);
923                 addState(mL2ConnectedState, mConnectingOrConnectedState); {
924                     addState(mWaitBeforeL3ProvisioningState, mL2ConnectedState);
925                     addState(mL3ProvisioningState, mL2ConnectedState);
926                     addState(mL3ConnectedState, mL2ConnectedState);
927                     addState(mRoamingState, mL2ConnectedState);
928                 }
929             }
930             addState(mDisconnectedState, mConnectableState);
931         }
932 
933         setInitialState(mDisconnectedState);
934 
935         setLogOnlyTransitions(false);
936 
937         // Start the StateMachine
938         start();
939 
940         // update with initial role for ConcreteClientModeManager
941         onRoleChanged();
942         // Update current connection wifiInfo
943         updateCurrentConnectionInfo();
944     }
945 
946     private static final int[] WIFI_MONITOR_EVENTS = {
947             WifiMonitor.TARGET_BSSID_EVENT,
948             WifiMonitor.ASSOCIATED_BSSID_EVENT,
949             WifiMonitor.ANQP_DONE_EVENT,
950             WifiMonitor.ASSOCIATION_REJECTION_EVENT,
951             WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
952             WifiMonitor.GAS_QUERY_DONE_EVENT,
953             WifiMonitor.GAS_QUERY_START_EVENT,
954             WifiMonitor.HS20_REMEDIATION_EVENT,
955             WifiMonitor.HS20_DEAUTH_IMMINENT_EVENT,
956             WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT,
957             WifiMonitor.NETWORK_CONNECTION_EVENT,
958             WifiMonitor.NETWORK_DISCONNECTION_EVENT,
959             WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
960             WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
961             WifiMonitor.SUP_REQUEST_IDENTITY,
962             WifiMonitor.SUP_REQUEST_SIM_AUTH,
963             WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE,
964             WifiMonitor.TRANSITION_DISABLE_INDICATION,
965             WifiMonitor.NETWORK_NOT_FOUND_EVENT,
966             WifiMonitor.TOFU_CERTIFICATE_EVENT,
967             WifiMonitor.AUXILIARY_SUPPLICANT_EVENT,
968             WifiMonitor.QOS_POLICY_RESET_EVENT,
969             WifiMonitor.QOS_POLICY_REQUEST_EVENT,
970             WifiMonitor.BSS_FREQUENCY_CHANGED_EVENT,
971     };
972 
registerForWifiMonitorEvents()973     private void registerForWifiMonitorEvents()  {
974         for (int event : WIFI_MONITOR_EVENTS) {
975             mWifiMonitor.registerHandler(mInterfaceName, event, getHandler());
976         }
977 
978         mWifiMetrics.registerForWifiMonitorEvents(mInterfaceName);
979         mWifiLastResortWatchdog.registerForWifiMonitorEvents(mInterfaceName);
980     }
981 
deregisterForWifiMonitorEvents()982     private void deregisterForWifiMonitorEvents()  {
983         for (int event : WIFI_MONITOR_EVENTS) {
984             mWifiMonitor.deregisterHandler(mInterfaceName, event, getHandler());
985         }
986 
987         mWifiMetrics.deregisterForWifiMonitorEvents(mInterfaceName);
988         mWifiLastResortWatchdog.deregisterForWifiMonitorEvents(mInterfaceName);
989     }
990 
isValidBssid(String bssidStr)991     private static boolean isValidBssid(String bssidStr) {
992         try {
993             MacAddress bssid = MacAddress.fromString(bssidStr);
994             return !Objects.equals(bssid, WifiManager.ALL_ZEROS_MAC_ADDRESS);
995         } catch (IllegalArgumentException e) {
996             return false;
997         }
998     }
999 
setMulticastFilter(boolean enabled)1000     private void setMulticastFilter(boolean enabled) {
1001         if (mIpClient != null) {
1002             mIpClient.setMulticastFilter(enabled);
1003         }
1004     }
1005 
1006     /*
1007      * Log wifi event to SecurityLog if the event occurred on a managed network.
1008      */
logEventIfManagedNetwork(@ullable WifiConfiguration config, @SupplicantEventCode int eventCode, MacAddress bssid, String reasonString)1009     private void logEventIfManagedNetwork(@Nullable WifiConfiguration config,
1010             @SupplicantEventCode int eventCode, MacAddress bssid, String reasonString) {
1011         if (config == null || !mWifiPermissionsUtil
1012                 .isAdmin(config.creatorUid, config.creatorName)) {
1013             return;
1014         }
1015 
1016         if (SdkLevel.isAtLeastT()) {
1017             int numRedactedOctets = mContext.getResources()
1018                     .getInteger(R.integer.config_wifiNumMaskedBssidOctetsInSecurityLog);
1019             String redactedBssid = ScanResultUtil.redactBssid(bssid, numRedactedOctets);
1020             if (eventCode == SupplicantStaIfaceHal.SUPPLICANT_EVENT_DISCONNECTED) {
1021                 SecurityLog.writeEvent(SecurityLog.TAG_WIFI_DISCONNECTION, redactedBssid,
1022                         reasonString);
1023             } else {
1024                 SecurityLog.writeEvent(SecurityLog.TAG_WIFI_CONNECTION, redactedBssid,
1025                         SupplicantStaIfaceHal.supplicantEventCodeToString(eventCode), reasonString);
1026             }
1027         }
1028     }
1029 
clearQueuedQosMessages()1030     protected void clearQueuedQosMessages() {
1031         removeMessages(WifiMonitor.QOS_POLICY_RESET_EVENT);
1032         removeMessages(WifiMonitor.QOS_POLICY_REQUEST_EVENT);
1033     }
1034 
1035     /**
1036      * Class to implement the MulticastLockManager.FilterController callback.
1037      */
1038     class McastLockManagerFilterController implements WifiMulticastLockManager.FilterController {
1039         /**
1040          * Start filtering Multicast v4 packets
1041          */
startFilteringMulticastPackets()1042         public void startFilteringMulticastPackets() {
1043             setMulticastFilter(true);
1044         }
1045 
1046         /**
1047          * Stop filtering Multicast v4 packets
1048          */
stopFilteringMulticastPackets()1049         public void stopFilteringMulticastPackets() {
1050             setMulticastFilter(false);
1051         }
1052     }
1053 
1054     class IpClientCallbacksImpl extends IpClientCallbacks {
1055         private final ConditionVariable mWaitForCreationCv = new ConditionVariable(false);
1056         private final ConditionVariable mWaitForStopCv = new ConditionVariable(false);
1057         private int mIpClientCallbacksIndex;
1058 
IpClientCallbacksImpl()1059         private IpClientCallbacksImpl() {
1060             mIpClientCallbacksIndex = ++sIpClientCallbacksIndex;
1061         }
1062 
1063         @Override
onIpClientCreated(IIpClient ipClient)1064         public void onIpClientCreated(IIpClient ipClient) {
1065             if (mIpClientCallbacks != this) return;
1066             // IpClient may take a very long time (many minutes) to start at boot time. But after
1067             // that IpClient should start pretty quickly (a few seconds).
1068             // Blocking wait for 5 seconds first (for when the wait is short)
1069             // If IpClient is still not ready after blocking wait, async wait (for when wait is
1070             // long). Will drop all connection requests until IpClient is ready. Other requests
1071             // will still be processed.
1072             sendMessageAtFrontOfQueue(CMD_IPCLIENT_CREATED, mIpClientCallbacksIndex, 0,
1073                     new IpClientManager(ipClient, getName()));
1074             mWaitForCreationCv.open();
1075         }
1076 
1077         @Override
onPreDhcpAction()1078         public void onPreDhcpAction() {
1079             sendMessage(CMD_PRE_DHCP_ACTION, mIpClientCallbacksIndex);
1080         }
1081 
1082         @Override
onPostDhcpAction()1083         public void onPostDhcpAction() {
1084             sendMessage(CMD_POST_DHCP_ACTION, mIpClientCallbacksIndex);
1085         }
1086 
1087         @Override
onNewDhcpResults(DhcpResultsParcelable dhcpResults)1088         public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
1089             if (dhcpResults != null) {
1090                 sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, mIpClientCallbacksIndex, 0, dhcpResults);
1091             } else {
1092                 sendMessage(CMD_IPV4_PROVISIONING_FAILURE, mIpClientCallbacksIndex);
1093             }
1094         }
1095 
1096         @Override
onProvisioningSuccess(LinkProperties newLp)1097         public void onProvisioningSuccess(LinkProperties newLp) {
1098             addPasspointInfoToLinkProperties(newLp);
1099             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL);
1100             sendMessage(CMD_UPDATE_LINKPROPERTIES, mIpClientCallbacksIndex, 0, newLp);
1101             sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL, mIpClientCallbacksIndex);
1102         }
1103 
1104         @Override
onProvisioningFailure(LinkProperties newLp)1105         public void onProvisioningFailure(LinkProperties newLp) {
1106             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST);
1107             sendMessage(CMD_IP_CONFIGURATION_LOST, mIpClientCallbacksIndex);
1108         }
1109 
1110         @Override
onLinkPropertiesChange(LinkProperties newLp)1111         public void onLinkPropertiesChange(LinkProperties newLp) {
1112             addPasspointInfoToLinkProperties(newLp);
1113             sendMessage(CMD_UPDATE_LINKPROPERTIES, mIpClientCallbacksIndex, 0, newLp);
1114         }
1115 
1116         @Override
onReachabilityLost(String logMsg)1117         public void onReachabilityLost(String logMsg) {
1118             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_IP_REACHABILITY_LOST);
1119             sendMessage(CMD_IP_REACHABILITY_LOST, mIpClientCallbacksIndex, 0, logMsg);
1120         }
1121 
1122         @Override
onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo)1123         public void onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo) {
1124             sendMessage(CMD_IP_REACHABILITY_FAILURE, mIpClientCallbacksIndex, 0, lossInfo);
1125         }
1126 
1127         @Override
installPacketFilter(byte[] filter)1128         public void installPacketFilter(byte[] filter) {
1129             sendMessage(CMD_INSTALL_PACKET_FILTER, mIpClientCallbacksIndex, 0, filter);
1130         }
1131 
1132         @Override
startReadPacketFilter()1133         public void startReadPacketFilter() {
1134             sendMessage(CMD_READ_PACKET_FILTER, mIpClientCallbacksIndex);
1135         }
1136 
1137         @Override
setFallbackMulticastFilter(boolean enabled)1138         public void setFallbackMulticastFilter(boolean enabled) {
1139             sendMessage(CMD_SET_FALLBACK_PACKET_FILTERING, mIpClientCallbacksIndex, 0, enabled);
1140         }
1141 
1142         @Override
setNeighborDiscoveryOffload(boolean enabled)1143         public void setNeighborDiscoveryOffload(boolean enabled) {
1144             sendMessage(CMD_CONFIG_ND_OFFLOAD, mIpClientCallbacksIndex, (enabled ? 1 : 0));
1145         }
1146 
1147         @Override
onPreconnectionStart(List<Layer2PacketParcelable> packets)1148         public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {
1149             sendMessage(CMD_START_FILS_CONNECTION, mIpClientCallbacksIndex, 0, packets);
1150         }
1151 
1152         @Override
setMaxDtimMultiplier(int multiplier)1153         public void setMaxDtimMultiplier(int multiplier) {
1154             sendMessage(CMD_SET_MAX_DTIM_MULTIPLIER, mIpClientCallbacksIndex, multiplier);
1155         }
1156 
1157         @Override
onQuit()1158         public void onQuit() {
1159             if (mIpClientCallbacks != this) return;
1160             mWaitForStopCv.open();
1161         }
1162 
awaitCreation()1163         boolean awaitCreation() {
1164             return mWaitForCreationCv.block(IPCLIENT_STARTUP_TIMEOUT_MS);
1165         }
1166 
awaitShutdown()1167         boolean awaitShutdown() {
1168             return mWaitForStopCv.block(IPCLIENT_SHUTDOWN_TIMEOUT_MS);
1169         }
1170 
getCallbackIndex()1171         int getCallbackIndex() {
1172             return mIpClientCallbacksIndex;
1173         }
1174     }
1175 
stopIpClient()1176     private void stopIpClient() {
1177         if (mVerboseLoggingEnabled) {
1178             Log.v(getTag(), "stopIpClient IpClientWithPreConnection: "
1179                     + mIpClientWithPreConnection);
1180         }
1181         if (mIpClient != null) {
1182             if (mIpClientWithPreConnection) {
1183                 mIpClient.notifyPreconnectionComplete(false);
1184             }
1185             mIpClient.stop();
1186         }
1187         mIpClientWithPreConnection = false;
1188         mSentHLPs = false;
1189     }
1190 
stopDhcpSetup()1191     private void stopDhcpSetup() {
1192         /* Restore power save and suspend optimizations */
1193         handlePostDhcpSetup();
1194         stopIpClient();
1195     }
1196 
convertToInternalDhcpOptions(List<android.net.DhcpOption> options)1197     private List<DhcpOption> convertToInternalDhcpOptions(List<android.net.DhcpOption> options) {
1198         List<DhcpOption> internalOptions = new ArrayList<DhcpOption>();
1199         for (android.net.DhcpOption option : options) {
1200             DhcpOption internalOption = new DhcpOption();
1201             internalOption.type = option.getType();
1202             if (option.getValue() != null) {
1203                 byte[] value = option.getValue();
1204                 internalOption.value = Arrays.copyOf(value, value.length);
1205             }
1206             internalOptions.add(internalOption);
1207         }
1208         return internalOptions;
1209     }
1210 
1211     /**
1212      * Listener for config manager network config related events.
1213      * TODO (b/117601161) : Move some of the existing handling in WifiConnectivityManager's listener
1214      * for the same events.
1215      */
1216     private class OnNetworkUpdateListener implements
1217             WifiConfigManager.OnNetworkUpdateListener {
1218         @Override
onNetworkRemoved(WifiConfiguration config)1219         public void onNetworkRemoved(WifiConfiguration config) {
1220             // The current connected or connecting network has been removed, trigger a disconnect.
1221             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1222                 // Disconnect and let autojoin reselect a new network
1223                 mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_REMOVED;
1224                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_REMOVED);
1225                 // Log disconnection here, since the network config won't exist when the
1226                 // disconnection event is received.
1227                 String bssid = getConnectedBssidInternal();
1228                 logEventIfManagedNetwork(config,
1229                         SupplicantStaIfaceHal.SUPPLICANT_EVENT_DISCONNECTED,
1230                         bssid != null ? MacAddress.fromString(bssid) : null,
1231                         "Network was removed");
1232             } else {
1233                 WifiConfiguration currentConfig = getConnectedWifiConfiguration();
1234                 if (currentConfig != null && currentConfig.isLinked(config)) {
1235                     logi("current network linked config removed, update allowlist networks");
1236                     updateLinkedNetworks(currentConfig);
1237                 }
1238             }
1239             mWifiNative.removeNetworkCachedData(config.networkId);
1240         }
1241 
1242         @Override
onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig, boolean hasCredentialChanged)1243         public void onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig,
1244                 boolean hasCredentialChanged) {
1245             if (hasCredentialChanged) {
1246                 // Clear invalid cached data.
1247                 mWifiNative.removeNetworkCachedData(oldConfig.networkId);
1248                 mWifiBlocklistMonitor.handleNetworkRemoved(newConfig.SSID);
1249             }
1250 
1251             if (newConfig.networkId != mLastNetworkId)  {
1252                 // nothing to do.
1253                 return;
1254             }
1255 
1256             if (newConfig.isWifi7Enabled() != oldConfig.isWifi7Enabled()) {
1257                 Log.w(getTag(), "Wi-Fi " + (newConfig.isWifi7Enabled() ? "enabled" : "disabled")
1258                         + " triggering disconnect");
1259                 mFrameworkDisconnectReasonOverride =
1260                         WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_WIFI7_TOGGLED;
1261                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_WIFI7_TOGGLED);
1262                 return;
1263             }
1264 
1265             boolean isMetered = WifiConfiguration.isMetered(newConfig, mWifiInfo);
1266             boolean wasMetered = WifiConfiguration.isMetered(oldConfig, mWifiInfo);
1267             // Check if user/app change meteredOverride or trusted for connected network.
1268             if (isMetered == wasMetered
1269                     && (!SdkLevel.isAtLeastT() || newConfig.trusted == oldConfig.trusted)) {
1270                 return;
1271             }
1272 
1273             if (SdkLevel.isAtLeastT()) {
1274                 mWifiInfo.setTrusted(newConfig.trusted);
1275                 if (!newConfig.trusted) {
1276                     Log.w(getTag(), "Network marked untrusted, triggering disconnect");
1277                     mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_UNTRUSTED;
1278                     sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_UNTRUSTED);
1279                     return;
1280                 }
1281             }
1282 
1283             if (isMetered) {
1284                 Log.w(getTag(), "Network marked metered, triggering disconnect");
1285                 mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_METERED;
1286                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_METERED);
1287                 return;
1288             }
1289 
1290             Log.i(getTag(), "Network marked metered=" + isMetered
1291                     + " trusted=" + newConfig.trusted + ", triggering capabilities update");
1292             updateCapabilities(newConfig);
1293             updateCurrentConnectionInfo();
1294         }
1295 
1296         @Override
onNetworkTemporarilyDisabled(WifiConfiguration config, int disableReason)1297         public void onNetworkTemporarilyDisabled(WifiConfiguration config, int disableReason) {
1298             if (disableReason == DISABLED_NO_INTERNET_TEMPORARY) return;
1299             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1300                 // Disconnect and let autojoin reselect a new network
1301                 mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_TEMP_DISABLED;
1302                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_TEMPORARY_DISABLED);
1303             }
1304 
1305         }
1306 
1307         @Override
onNetworkPermanentlyDisabled(WifiConfiguration config, int disableReason)1308         public void onNetworkPermanentlyDisabled(WifiConfiguration config, int disableReason) {
1309             // For DISABLED_NO_INTERNET_PERMANENT we do not need to remove the network
1310             // because supplicant won't be trying to reconnect. If this is due to a
1311             // preventAutomaticReconnect request from ConnectivityService, that service
1312             // will disconnect as appropriate.
1313             if (disableReason == DISABLED_NO_INTERNET_PERMANENT) return;
1314             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1315                 // Disconnect and let autojoin reselect a new network
1316                 mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_PERM_DISABLED;
1317                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_PERMANENT_DISABLED);
1318             }
1319         }
1320     }
1321 
1322     private class OnCarrierOffloadDisabledListener implements
1323             WifiCarrierInfoManager.OnCarrierOffloadDisabledListener {
1324 
1325         @Override
onCarrierOffloadDisabled(int subscriptionId, boolean merged)1326         public void onCarrierOffloadDisabled(int subscriptionId, boolean merged) {
1327             int networkId = mTargetNetworkId == WifiConfiguration.INVALID_NETWORK_ID
1328                     ? mLastNetworkId : mTargetNetworkId;
1329             if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1330                 return;
1331             }
1332             WifiConfiguration configuration = mWifiConfigManager.getConfiguredNetwork(networkId);
1333             if (configuration != null && configuration.subscriptionId == subscriptionId
1334                     && configuration.carrierMerged == merged) {
1335                 Log.i(getTag(), "Carrier network offload disabled, triggering disconnect");
1336                 mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_CARRIER_OFFLOAD_DISABLED;
1337                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_CARRIER_OFFLOAD_DISABLED);
1338             }
1339             mWifiConnectivityManager.clearCachedCandidates();
1340         }
1341     }
1342 
1343     /**
1344      * Method to update logging level in wifi service related classes.
1345      *
1346      * @param verbose int logging level to use
1347      */
enableVerboseLogging(boolean verbose)1348     public void enableVerboseLogging(boolean verbose) {
1349         if (verbose) {
1350             mVerboseLoggingEnabled = true;
1351             setLogRecSize(mActivityManager.isLowRamDevice()
1352                     ? NUM_LOG_RECS_VERBOSE_LOW_MEMORY : NUM_LOG_RECS_VERBOSE);
1353         } else {
1354             mVerboseLoggingEnabled = false;
1355             setLogRecSize(mWifiGlobals.getClientModeImplNumLogRecs());
1356         }
1357 
1358         mWifiScoreReport.enableVerboseLogging(mVerboseLoggingEnabled);
1359         mSupplicantStateTracker.enableVerboseLogging(mVerboseLoggingEnabled);
1360         mWifiNative.enableVerboseLogging(mVerboseLoggingEnabled, mVerboseLoggingEnabled);
1361         mQosPolicyRequestHandler.enableVerboseLogging(mVerboseLoggingEnabled);
1362         mRssiMonitor.enableVerboseLogging(mVerboseLoggingEnabled);
1363     }
1364 
1365     /**
1366      * If there is only SAE-only networks with this auto-upgrade type,
1367      * this auto-upgrade SAE type is considered to be added explicitly.
1368      *
1369      * For R, Settings/WifiTrackerLib maps WPA3 SAE to WPA2, so there is
1370      * no chance to add or update a WPA3 SAE configuration to update
1371      * the auto-upgrade flag.
1372      */
updateSaeAutoUpgradeFlagForUserSelectNetwork(int networkId)1373     private void updateSaeAutoUpgradeFlagForUserSelectNetwork(int networkId) {
1374         if (SdkLevel.isAtLeastS()) return;
1375         if (mWifiGlobals.isWpa3SaeUpgradeEnabled()) return;
1376 
1377         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId);
1378         if (null == config) return;
1379         SecurityParams params = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
1380         if (null == params || !params.isAddedByAutoUpgrade()) return;
1381 
1382         if (!mScanRequestProxy.isWpa3PersonalOnlyNetworkInRange(config.SSID)) return;
1383         if (mScanRequestProxy.isWpa2PersonalOnlyNetworkInRange(config.SSID)) return;
1384         if (mScanRequestProxy.isWpa2Wpa3PersonalTransitionNetworkInRange(config.SSID)) return;
1385 
1386         logd("update auto-upgrade flag for SAE");
1387         mWifiConfigManager.updateIsAddedByAutoUpgradeFlag(
1388                 config.networkId, WifiConfiguration.SECURITY_TYPE_SAE, false);
1389     }
1390 
1391     /**
1392      * Given a network ID for connection, check the security parameters for a
1393      * disabled security type.
1394      *
1395      * Allow the connection only when there are APs with the better security
1396      * type (or transition mode), or no APs with the disabled security type.
1397      *
1398      * @param networkIdForConnection indicates the network id for the desired connection.
1399      * @return {@code true} if this connection request should be dropped; {@code false} otherwise.
1400      */
shouldDropConnectionRequest(int networkIdForConnection)1401     private boolean shouldDropConnectionRequest(int networkIdForConnection) {
1402         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkIdForConnection);
1403         if (null == config) return false;
1404 
1405         List<ScanResult> scanResults = mScanRequestProxy.getScanResults().stream()
1406                 .filter(r -> TextUtils.equals(config.SSID, r.getWifiSsid().toString()))
1407                 .collect(Collectors.toList());
1408         if (0 == scanResults.size()) return false;
1409 
1410         SecurityParams params;
1411         // Check disabled PSK network.
1412         params = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
1413         if (null != params && !params.isEnabled()) {
1414             if (scanResults.stream().anyMatch(r ->
1415                     ScanResultUtil.isScanResultForSaeNetwork(r))) {
1416                 return false;
1417             }
1418             if (!scanResults.stream().anyMatch(r ->
1419                     ScanResultUtil.isScanResultForPskOnlyNetwork(r))) {
1420                 return false;
1421             }
1422             return true;
1423         }
1424         // Check disabled OPEN network.
1425         params = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
1426         if (null != params && !params.isEnabled()) {
1427             if (scanResults.stream().anyMatch(r ->
1428                     ScanResultUtil.isScanResultForOweNetwork(r))) {
1429                 return false;
1430             }
1431             if (!scanResults.stream().anyMatch(r ->
1432                     ScanResultUtil.isScanResultForOpenOnlyNetwork(r))) {
1433                 return false;
1434             }
1435             return true;
1436         }
1437         // Check disabled WPA2 Enterprise network.
1438         params = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
1439         if (null != params && !params.isEnabled()) {
1440             if (scanResults.stream().anyMatch(r ->
1441                     ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(r))) {
1442                 return false;
1443             }
1444             if (scanResults.stream().anyMatch(r ->
1445                     ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(r))) {
1446                 return false;
1447             }
1448             if (!scanResults.stream().anyMatch(r ->
1449                     ScanResultUtil.isScanResultForWpa2EnterpriseOnlyNetwork(r))) {
1450                 return false;
1451             }
1452             return true;
1453         }
1454         return false;
1455     }
1456 
1457     /**
1458      * Initiates connection to a network specified by the user/app. This method checks if the
1459      * requesting app holds the NETWORK_SETTINGS permission.
1460      *
1461      * @param netId Id network to initiate connection.
1462      * @param uid UID of the app requesting the connection.
1463      * @param forceReconnect Whether to force a connection even if we're connected to the same
1464      *                       network currently.
1465      * @param packageName package name of the app requesting the connection.
1466      */
connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect, @NonNull String packageName, @Nullable String attributionTag)1467     private void connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect,
1468             @NonNull String packageName, @Nullable String attributionTag) {
1469         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
1470                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
1471             mIsUserSelected = true;
1472         }
1473         logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid + ", package "
1474                 + packageName + ", forceReconnect = " + forceReconnect + ", isUserSelected = "
1475                 + mIsUserSelected + ", attributionTag = " + attributionTag);
1476         updateSaeAutoUpgradeFlagForUserSelectNetwork(netId);
1477         if (!forceReconnect && (mLastNetworkId == netId || mTargetNetworkId == netId)) {
1478             // We're already connecting/connected to the user specified network, don't trigger a
1479             // reconnection unless it was forced.
1480             logi("connectToUserSelectNetwork already connecting/connected=" + netId);
1481         } else if (mIsUserSelected && shouldDropConnectionRequest(netId)) {
1482             logi("connectToUserSelectNetwork this network is disabled by admin.");
1483             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
1484             String title = mContext.getString(R.string.wifi_network_disabled_by_admin_title);
1485             String message = mContext.getString(R.string.wifi_network_disabled_by_admin_message,
1486                     config.SSID);
1487             String buttonText = mContext.getString(R.string.wifi_network_disabled_by_admin_button);
1488             mWifiInjector.getWifiDialogManager().createLegacySimpleDialog(
1489                     title, message,
1490                     null /* positiveButtonText */,
1491                     null /* negativeButtonText */,
1492                     buttonText,
1493                     new WifiDialogManager.SimpleDialogCallback() {
1494                         @Override
1495                         public void onPositiveButtonClicked() {
1496                             // Not used.
1497                         }
1498                         @Override
1499                         public void onNegativeButtonClicked() {
1500                             // Not used.
1501                         }
1502                         @Override
1503                         public void onNeutralButtonClicked() {
1504                             // Not used.
1505                         }
1506                         @Override
1507                         public void onCancelled() {
1508                             // Not used.
1509                         }
1510                     }, mWifiThreadRunner).launchDialog();
1511         } else {
1512             if (mIsUserSelected && ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE.equals(attributionTag)) {
1513                 mIsUserSelected = false;
1514                 logd("connectToUserSelectNetwork attributionTag override to disable user selected");
1515             }
1516             mWifiConnectivityManager.prepareForForcedConnection(netId);
1517             if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
1518                 mWifiMetrics.setNominatorForNetwork(netId,
1519                         WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL);
1520             }
1521             startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
1522         }
1523     }
1524 
1525     /**
1526      * ******************************************************
1527      * Methods exposed for public use
1528      * ******************************************************
1529      */
1530 
1531     /**
1532      * Retrieve a Messenger for the ClientModeImpl Handler
1533      *
1534      * @return Messenger
1535      */
getMessenger()1536     public Messenger getMessenger() {
1537         return new Messenger(getHandler());
1538     }
1539 
1540     // For debugging, keep track of last message status handling
1541     // TODO, find an equivalent mechanism as part of parent class
1542     private static final int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
1543     private static final int MESSAGE_HANDLING_STATUS_OK = 1;
1544     private static final int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
1545     private static final int MESSAGE_HANDLING_STATUS_REFUSED = -1;
1546     private static final int MESSAGE_HANDLING_STATUS_FAIL = -2;
1547     private static final int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
1548     private static final int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
1549     private static final int MESSAGE_HANDLING_STATUS_DISCARD = -5;
1550     private static final int MESSAGE_HANDLING_STATUS_LOOPED = -6;
1551     private static final int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
1552 
1553     private int mMessageHandlingStatus = 0;
1554 
1555     private int mOnTime = 0;
1556     private int mTxTime = 0;
1557     private int mRxTime = 0;
1558 
1559     private int mOnTimeScreenStateChange = 0;
1560     private long mLastOntimeReportTimeStamp = 0;
1561     private long mLastScreenStateChangeTimeStamp = 0;
1562     private int mOnTimeLastReport = 0;
1563     private int mTxTimeLastReport = 0;
1564     private int mRxTimeLastReport = 0;
1565 
1566     private WifiLinkLayerStats mLastLinkLayerStats;
1567     private long mLastLinkLayerStatsUpdate = 0;
1568 
reportOnTime()1569     String reportOnTime() {
1570         long now = mClock.getWallClockMillis();
1571         StringBuilder sb = new StringBuilder();
1572         // Report stats since last report
1573         int on = mOnTime - mOnTimeLastReport;
1574         mOnTimeLastReport = mOnTime;
1575         int tx = mTxTime - mTxTimeLastReport;
1576         mTxTimeLastReport = mTxTime;
1577         int rx = mRxTime - mRxTimeLastReport;
1578         mRxTimeLastReport = mRxTime;
1579         int period = (int) (now - mLastOntimeReportTimeStamp);
1580         mLastOntimeReportTimeStamp = now;
1581         sb.append("[on:" + on + " tx:" + tx + " rx:" + rx + " period:" + period + "]");
1582         // Report stats since Screen State Changed
1583         on = mOnTime - mOnTimeScreenStateChange;
1584         period = (int) (now - mLastScreenStateChangeTimeStamp);
1585         sb.append(" from screen [on:" + on + " period:" + period + "]");
1586         return sb.toString();
1587     }
1588 
1589     /**
1590      * receives changes in the interface up/down events for the interface associated with this
1591      * ClientModeImpl. This is expected to be called from the ClientModeManager running on the
1592      * wifi handler thread.
1593      */
onUpChanged(boolean isUp)1594     public void onUpChanged(boolean isUp) {
1595         if (isUp && mFailedToResetMacAddress) {
1596             // When the firmware does a subsystem restart, wifi will disconnect but we may fail to
1597             // re-randomize the MAC address of the interface since it's undergoing recovery. Thus,
1598             // check every time the interface goes up and re-randomize if the failure was detected.
1599             if (mWifiGlobals.isConnectedMacRandomizationEnabled()) {
1600                 mFailedToResetMacAddress = !mWifiNative.setStaMacAddress(
1601                         mInterfaceName, MacAddressUtils.createRandomUnicastAddress());
1602                 if (mFailedToResetMacAddress) {
1603                     Log.e(getTag(), "Failed to set random MAC address on interface up");
1604                 }
1605             }
1606         }
1607         // No need to handle interface down since it's already handled in the ClientModeManager.
1608     }
1609 
getWifiLinkLayerStats()1610     public WifiLinkLayerStats getWifiLinkLayerStats() {
1611         if (mInterfaceName == null) {
1612             loge("getWifiLinkLayerStats called without an interface");
1613             return null;
1614         }
1615         mLastLinkLayerStatsUpdate = mClock.getWallClockMillis();
1616         WifiLinkLayerStats stats = null;
1617         if (isLinkLayerStatsSupported()) {
1618             if (isPrimary()) {
1619                 stats = mWifiNative.getWifiLinkLayerStats(mInterfaceName);
1620             } else {
1621                 if (mVerboseLoggingEnabled) {
1622                     Log.w(getTag(), "Can't getWifiLinkLayerStats on secondary iface");
1623                 }
1624             }
1625         }
1626         if (stats != null) {
1627             mOnTime = stats.on_time;
1628             mTxTime = stats.tx_time;
1629             mRxTime = stats.rx_time;
1630             mRunningBeaconCount = stats.beacon_rx;
1631             mWifiInfo.updatePacketRates(stats, mLastLinkLayerStatsUpdate);
1632         } else {
1633             long mTxPkts = mFacade.getTxPackets(mInterfaceName);
1634             long mRxPkts = mFacade.getRxPackets(mInterfaceName);
1635             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts, mLastLinkLayerStatsUpdate);
1636         }
1637         mWifiMetrics.incrementWifiLinkLayerUsageStats(mInterfaceName, stats);
1638         updateCurrentConnectionInfo();
1639         return stats;
1640     }
1641 
isLinkLayerStatsSupported()1642     private boolean isLinkLayerStatsSupported() {
1643         return (getSupportedFeatures() & WIFI_FEATURE_LINK_LAYER_STATS) != 0;
1644     }
1645 
1646     /**
1647      * Update interface capabilities
1648      * This method is used to update some of interface capabilities defined in overlay
1649      */
updateInterfaceCapabilities()1650     private void updateInterfaceCapabilities() {
1651         DeviceWiphyCapabilities cap = getDeviceWiphyCapabilities();
1652         if (cap != null) {
1653             // Some devices don't have support of 11ax/be indicated by the chip,
1654             // so an override config value is used
1655             if (mContext.getResources().getBoolean(R.bool.config_wifi11beSupportOverride)) {
1656                 cap.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11BE, true);
1657             }
1658             if (mContext.getResources().getBoolean(R.bool.config_wifi11axSupportOverride)) {
1659                 cap.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, true);
1660             }
1661             // The Wi-Fi Alliance has introduced the WPA3 security update for Wi-Fi 7, which
1662             // mandates cross-AKM (Authenticated Key Management) roaming between three AKMs
1663             // (AKM: 24(SAE-EXT-KEY), AKM:8(SAE) and AKM:2(PSK)). If the station supports
1664             // AKM 24(SAE-EXT-KEY), it is recommended to enable WPA3 SAE auto-upgrade offload,
1665             // provided that the driver indicates that the maximum number of AKM suites allowed in
1666             // connection requests is three or more.
1667             if (Flags.getDeviceCrossAkmRoamingSupport() && SdkLevel.isAtLeastV()
1668                     && cap.getMaxNumberAkms() >= 3) {
1669                 mWifiGlobals.setWpa3SaeUpgradeOffloadEnabled();
1670             }
1671 
1672             mWifiNative.setDeviceWiphyCapabilities(mInterfaceName, cap);
1673         }
1674     }
1675 
1676     @Override
getDeviceWiphyCapabilities()1677     public DeviceWiphyCapabilities getDeviceWiphyCapabilities() {
1678         return mWifiNative.getDeviceWiphyCapabilities(mInterfaceName);
1679     }
1680 
1681     /**
1682      * Check if a Wi-Fi standard is supported
1683      *
1684      * @param standard A value from {@link ScanResult}'s {@code WIFI_STANDARD_}
1685      * @return {@code true} if standard is supported, {@code false} otherwise.
1686      */
isWifiStandardSupported(@ifiStandard int standard)1687     public boolean isWifiStandardSupported(@WifiStandard int standard) {
1688         return mWifiNative.isWifiStandardSupported(mInterfaceName, standard);
1689     }
1690 
1691     /**
1692      * Check whether 11ax is supported by the most recent connection.
1693      */
mostRecentConnectionSupports11ax()1694     public boolean mostRecentConnectionSupports11ax() {
1695         return mLastConnectionCapabilities != null
1696                 && (mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11AX
1697                 || mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11BE);
1698     }
1699 
getDstMacForKeepalive(KeepalivePacketData packetData)1700     private byte[] getDstMacForKeepalive(KeepalivePacketData packetData)
1701             throws InvalidPacketException {
1702         try {
1703             InetAddress gateway = NetUtils.selectBestRoute(
1704                     mLinkProperties.getRoutes(), packetData.getDstAddress()).getGateway();
1705             String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
1706             return NativeUtil.macAddressToByteArray(dstMacStr);
1707         } catch (NullPointerException | IllegalArgumentException e) {
1708             throw new InvalidPacketException(InvalidPacketException.ERROR_INVALID_IP_ADDRESS);
1709         }
1710     }
1711 
getEtherProtoForKeepalive(KeepalivePacketData packetData)1712     private static int getEtherProtoForKeepalive(KeepalivePacketData packetData)
1713             throws InvalidPacketException {
1714         if (packetData.getDstAddress() instanceof Inet4Address) {
1715             return OsConstants.ETH_P_IP;
1716         } else if (packetData.getDstAddress() instanceof Inet6Address) {
1717             return OsConstants.ETH_P_IPV6;
1718         } else {
1719             throw new InvalidPacketException(InvalidPacketException.ERROR_INVALID_IP_ADDRESS);
1720         }
1721     }
1722 
startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds)1723     private int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData,
1724             int intervalSeconds) {
1725         byte[] packet = null;
1726         byte[] dstMac = null;
1727         int proto = 0;
1728 
1729         try {
1730             packet = packetData.getPacket();
1731             dstMac = getDstMacForKeepalive(packetData);
1732             proto = getEtherProtoForKeepalive(packetData);
1733         } catch (InvalidPacketException e) {
1734             return e.getError();
1735         }
1736 
1737         int ret = mWifiNative.startSendingOffloadedPacket(
1738                 mInterfaceName, slot, dstMac, packet, proto, intervalSeconds * 1000);
1739         if (ret != 0) {
1740             loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds
1741                     + "): hardware error " + ret);
1742             return SocketKeepalive.ERROR_HARDWARE_ERROR;
1743         } else {
1744             return SocketKeepalive.SUCCESS;
1745         }
1746     }
1747 
stopWifiIPPacketOffload(int slot)1748     private int stopWifiIPPacketOffload(int slot) {
1749         int ret = mWifiNative.stopSendingOffloadedPacket(mInterfaceName, slot);
1750         if (ret != 0) {
1751             loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret);
1752             return SocketKeepalive.ERROR_HARDWARE_ERROR;
1753         } else {
1754             return SocketKeepalive.SUCCESS;
1755         }
1756     }
1757 
1758     @Override
isConnected()1759     public boolean isConnected() {
1760         return getCurrentState() == mL3ConnectedState;
1761     }
1762 
1763     @Override
isConnecting()1764     public boolean isConnecting() {
1765         IState state = getCurrentState();
1766         return state == mL2ConnectingState || state == mL2ConnectedState
1767                 || state == mWaitBeforeL3ProvisioningState || state == mL3ProvisioningState;
1768     }
1769 
1770     @Override
isRoaming()1771     public boolean isRoaming() {
1772         return getCurrentState() == mRoamingState;
1773     }
1774 
1775     @Override
isDisconnected()1776     public boolean isDisconnected() {
1777         return getCurrentState() == mDisconnectedState;
1778     }
1779 
1780     /**
1781      * Method checking if supplicant is in a transient state
1782      *
1783      * @return boolean true if in transient state
1784      */
isSupplicantTransientState()1785     public boolean isSupplicantTransientState() {
1786         SupplicantState supplicantState = mWifiInfo.getSupplicantState();
1787         if (supplicantState == SupplicantState.ASSOCIATING
1788                 || supplicantState == SupplicantState.AUTHENTICATING
1789                 || supplicantState == SupplicantState.FOUR_WAY_HANDSHAKE
1790                 || supplicantState == SupplicantState.GROUP_HANDSHAKE) {
1791 
1792             if (mVerboseLoggingEnabled) {
1793                 Log.d(getTag(), "Supplicant is under transient state: " + supplicantState);
1794             }
1795             return true;
1796         } else {
1797             if (mVerboseLoggingEnabled) {
1798                 Log.d(getTag(), "Supplicant is under steady state: " + supplicantState);
1799             }
1800         }
1801 
1802         return false;
1803     }
1804 
1805     /**
1806      * Get status information for the current connection, if any.
1807      * Note: This call is synchronized and hence safe to call from any thread (if called from wifi
1808      * thread, will execute synchronously).
1809      *
1810      * @return a {@link WifiInfo} object containing information about the current connection
1811      */
1812     @Override
getConnectionInfo()1813     public WifiInfo getConnectionInfo() {
1814         return new WifiInfo(mWifiInfo);
1815     }
1816 
1817     /**
1818      * Blocking call to get the current DHCP results
1819      *
1820      * @return DhcpResultsParcelable current results
1821      */
1822     @NonNull
syncGetDhcpResultsParcelable()1823     public DhcpResultsParcelable syncGetDhcpResultsParcelable() {
1824         synchronized (mDhcpResultsParcelableLock) {
1825             return mDhcpResultsParcelable;
1826         }
1827     }
1828 
1829     /**
1830      * When the underlying interface is destroyed, we must immediately tell connectivity service to
1831      * mark network agent as disconnected and stop the ip client.
1832      */
handleIfaceDestroyed()1833     public void handleIfaceDestroyed() {
1834         handleNetworkDisconnect(false,
1835                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__IFACE_DESTROYED);
1836     }
1837 
1838     /** Stop this ClientModeImpl. Do not interact with ClientModeImpl after it has been stopped. */
stop()1839     public void stop() {
1840         mInsecureEapNetworkHandler.cleanup();
1841         mSupplicantStateTracker.stop();
1842         mWifiScoreCard.noteWifiDisabled(mWifiInfo);
1843         // capture StateMachine LogRecs since we will lose them after we call quitNow()
1844         // This is used for debugging.
1845         mObituary = new StateMachineObituary(this);
1846 
1847         // quit discarding all unprocessed messages - this is to preserve the legacy behavior of
1848         // using sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE) which would force a state
1849         // transition immediately
1850         quitNow();
1851 
1852         mWifiConfigManager.removeOnNetworkUpdateListener(mOnNetworkUpdateListener);
1853         mWifiCarrierInfoManager
1854                 .removeOnCarrierOffloadDisabledListener(mOnCarrierOffloadDisabledListener);
1855         if (mVcnPolicyChangeListener != null && SdkLevel.isAtLeastS()) {
1856             mVcnManager.removeVcnNetworkPolicyChangeListener(mVcnPolicyChangeListener);
1857             mVcnPolicyChangeListener = null;
1858         }
1859     }
1860 
checkAbnormalConnectionFailureAndTakeBugReport(String ssid)1861     private void checkAbnormalConnectionFailureAndTakeBugReport(String ssid) {
1862         if (mDeviceConfigFacade.isAbnormalConnectionFailureBugreportEnabled()) {
1863             int reasonCode = mWifiScoreCard.detectAbnormalConnectionFailure(ssid);
1864             if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) {
1865                 String bugTitle = "Wi-Fi BugReport: abnormal "
1866                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1867                 String bugDetail = "Detect abnormal "
1868                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1869                 mWifiDiagnostics.takeBugReport(bugTitle, bugDetail);
1870             }
1871         }
1872     }
1873 
checkAbnormalDisconnectionAndTakeBugReport()1874     private void checkAbnormalDisconnectionAndTakeBugReport() {
1875         if (mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()) {
1876             int reasonCode = mWifiScoreCard.detectAbnormalDisconnection(mInterfaceName);
1877             if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) {
1878                 String bugTitle = "Wi-Fi BugReport: abnormal "
1879                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1880                 String bugDetail = "Detect abnormal "
1881                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1882                 mWifiDiagnostics.takeBugReport(bugTitle, bugDetail);
1883             }
1884         }
1885     }
1886 
1887     /**
1888      * Retrieve the WifiMulticastLockManager.FilterController callback for registration.
1889      */
getMcastLockManagerFilterController()1890     public WifiMulticastLockManager.FilterController getMcastLockManagerFilterController() {
1891         return mMcastLockManagerFilterController;
1892     }
1893 
1894     /**
1895      * Blocking method to retrieve the passpoint icon.
1896      *
1897      * @param bssid representation of the bssid as a long
1898      * @param fileName name of the file
1899      *
1900      * @return boolean returning the result of the call
1901      */
syncQueryPasspointIcon(long bssid, String fileName)1902     public boolean syncQueryPasspointIcon(long bssid, String fileName) {
1903         return mWifiThreadRunner.call(
1904                 () -> mPasspointManager.queryPasspointIcon(bssid, fileName), false,
1905                 TAG + "#syncQueryPasspointIcon");
1906     }
1907 
1908     @Override
requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes)1909     public boolean requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes) {
1910         return mWifiNative.requestAnqp(mInterfaceName, bssid, anqpIds, hs20Subtypes);
1911     }
1912 
1913     @Override
requestVenueUrlAnqp(String bssid)1914     public boolean requestVenueUrlAnqp(String bssid) {
1915         return mWifiNative.requestVenueUrlAnqp(mInterfaceName, bssid);
1916     }
1917 
1918     @Override
requestIcon(String bssid, String fileName)1919     public boolean requestIcon(String bssid, String fileName) {
1920         return mWifiNative.requestIcon(mInterfaceName, bssid, fileName);
1921     }
1922 
1923     /**
1924      * Disconnect from Access Point
1925      */
disconnect()1926     public void disconnect() {
1927         mFrameworkDisconnectReasonOverride =
1928                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_GENERAL;
1929         sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_GENERIC);
1930     }
1931 
1932     /**
1933      * Initiate a reconnection to AP
1934      */
reconnect(WorkSource workSource)1935     public void reconnect(WorkSource workSource) {
1936         sendMessage(CMD_RECONNECT, workSource);
1937     }
1938 
1939     /**
1940      * Initiate a re-association to AP
1941      */
reassociate()1942     public void reassociate() {
1943         sendMessage(CMD_REASSOCIATE);
1944     }
1945 
1946     /**
1947      * Start subscription provisioning synchronously
1948      *
1949      * @param provider {@link OsuProvider} the provider to provision with
1950      * @param callback {@link IProvisioningCallback} callback for provisioning status
1951      * @return boolean true indicates provisioning was started, false otherwise
1952      */
syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, IProvisioningCallback callback)1953     public boolean syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider,
1954             IProvisioningCallback callback) {
1955         return mWifiThreadRunner.call(
1956                 () -> mPasspointManager.startSubscriptionProvisioning(
1957                         callingUid, provider, callback), false,
1958                 TAG + "#syncStartSubscriptionProvisioning");
1959     }
1960 
1961     /**
1962      * Get the supported feature set synchronously
1963      */
getSupportedFeatures()1964     public long getSupportedFeatures() {
1965         return mWifiNative.getSupportedFeatureSet(mInterfaceName);
1966     }
1967 
1968     /**
1969      * Method to enable/disable RSSI polling
1970      * @param enabled boolean idicating if polling should start
1971      */
1972     @VisibleForTesting
enableRssiPolling(boolean enabled)1973     public void enableRssiPolling(boolean enabled) {
1974         sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
1975     }
1976 
1977     /**
1978      * reset cached SIM credential data
1979      */
resetSimAuthNetworks(@esetSimReason int resetReason)1980     public void resetSimAuthNetworks(@ResetSimReason int resetReason) {
1981         sendMessage(CMD_RESET_SIM_NETWORKS, resetReason);
1982     }
1983 
1984     /**
1985      * Get Network object of currently connected wifi network, or null if not connected.
1986      * @return Network object of current wifi network
1987      */
getCurrentNetwork()1988     public Network getCurrentNetwork() {
1989         if (getCurrentState() != mL3ConnectedState
1990                 && getCurrentState() != mRoamingState) return null;
1991         return (mNetworkAgent != null) ? mNetworkAgent.getNetwork() : null;
1992     }
1993 
1994     /**
1995      * Enable TDLS for a specific MAC address
1996      */
enableTdls(String remoteMacAddress, boolean enable)1997     public boolean enableTdls(String remoteMacAddress, boolean enable) {
1998         boolean ret;
1999         if (enable && !canEnableTdls()) {
2000             return false;
2001         }
2002         ret = mWifiNative.startTdls(mInterfaceName, remoteMacAddress, enable);
2003         if (enable && ret) {
2004             mEnabledTdlsPeers.add(remoteMacAddress);
2005         } else {
2006             mEnabledTdlsPeers.remove(remoteMacAddress);
2007         }
2008         return ret;
2009     }
2010 
2011     /**
2012      * Enable TDLS for a specific IP address
2013      */
enableTdlsWithRemoteIpAddress(String remoteIpAddress, boolean enable)2014     public boolean enableTdlsWithRemoteIpAddress(String remoteIpAddress, boolean enable) {
2015         boolean ret;
2016         String remoteMacAddress = macAddressFromRoute(remoteIpAddress);
2017         if (remoteMacAddress == null) {
2018             return false;
2019         }
2020         ret = enableTdls(remoteMacAddress, enable);
2021         return ret;
2022     }
2023 
2024     /**
2025      *  Check if a TDLS session can be established
2026      */
isTdlsOperationCurrentlyAvailable()2027     public boolean isTdlsOperationCurrentlyAvailable() {
2028         return (getSupportedFeatures() & WIFI_FEATURE_TDLS) != 0 && isConnected()
2029                 && canEnableTdls();
2030     }
2031 
2032     /**
2033      *  Return the number of Mac addresses configured in the driver for TDLS connection.
2034      */
getNumberOfEnabledTdlsSessions()2035     public int getNumberOfEnabledTdlsSessions() {
2036         return mEnabledTdlsPeers.size();
2037     }
2038 
2039     /**
2040      *  Return the maximum number of TDLS sessions supported by the device.
2041      */
getMaxSupportedConcurrentTdlsSessions()2042     public int getMaxSupportedConcurrentTdlsSessions() {
2043         return mWifiNative.getMaxSupportedConcurrentTdlsSessions(mInterfaceName);
2044     }
2045 
canEnableTdls()2046     private boolean canEnableTdls() {
2047         // This function returns -1 if HAL doesn't have support for retrieving this info.
2048         int maxTdlsSessionCount = mWifiNative.getMaxSupportedConcurrentTdlsSessions(mInterfaceName);
2049         if (maxTdlsSessionCount < 0) {
2050             return true;
2051         }
2052         if (mEnabledTdlsPeers.size() >= maxTdlsSessionCount) {
2053             Log.e(TAG, "canEnableTdls() returned false: maxTdlsSessionCount: "
2054                     + maxTdlsSessionCount + "EnabledTdlsPeers count: " + mEnabledTdlsPeers.size());
2055             return false;
2056         }
2057         return true;
2058     }
2059 
2060     /** Send a message indicating bluetooth connection state changed, e.g. connected/disconnected */
onBluetoothConnectionStateChanged()2061     public void onBluetoothConnectionStateChanged() {
2062         sendMessage(CMD_BLUETOOTH_CONNECTION_STATE_CHANGE);
2063     }
2064 
2065     /**
2066      * Trigger dump on the class IpClient object.
2067      */
dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args)2068     public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) {
2069         if (mIpClient != null) {
2070             // All dumpIpClient does is print this log message.
2071             // TODO: consider deleting this, since it's not useful.
2072             pw.println("IpClient logs have moved to dumpsys network_stack");
2073         }
2074     }
2075 
dhcpResultsParcelableToString(DhcpResultsParcelable dhcpResults)2076     private static String dhcpResultsParcelableToString(DhcpResultsParcelable dhcpResults) {
2077         return new StringBuilder()
2078                 .append("baseConfiguration ").append(dhcpResults.baseConfiguration)
2079                 .append("leaseDuration ").append(dhcpResults.leaseDuration)
2080                 .append("mtu ").append(dhcpResults.mtu)
2081                 .append("serverAddress ").append(dhcpResults.serverAddress)
2082                 .append("serverHostName ").append(dhcpResults.serverHostName)
2083                 .append("vendorInfo ").append(dhcpResults.vendorInfo)
2084                 .toString();
2085     }
2086 
2087     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2088     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2089         pw.println("Dump of ClientModeImpl id=" + mId);
2090         if (mObituary == null) {
2091             // StateMachine hasn't quit yet, dump `this` via StateMachineObituary's dump()
2092             // method for consistency with `else` branch.
2093             new StateMachineObituary(this).dump(fd, pw, args);
2094         } else {
2095             // StateMachine has quit and cleared all LogRecs.
2096             // Get them from the obituary instead.
2097             mObituary.dump(fd, pw, args);
2098         }
2099         mSupplicantStateTracker.dump(fd, pw, args);
2100         // Polls link layer stats and RSSI. This allows the stats to show up in
2101         // WifiScoreReport's dump() output when taking a bug report even if the screen is off.
2102         updateLinkLayerStatsRssiAndScoreReport();
2103         pw.println("mLinkProperties " + mLinkProperties);
2104         pw.println("mWifiInfo " + mWifiInfo);
2105         pw.println("mDhcpResultsParcelable "
2106                 + dhcpResultsParcelableToString(mDhcpResultsParcelable));
2107         pw.println("mLastSignalLevel " + mLastSignalLevel);
2108         pw.println("mLastTxKbps " + mLastTxKbps);
2109         pw.println("mLastRxKbps " + mLastRxKbps);
2110         pw.println("mLastBssid " + mLastBssid);
2111         pw.println("mLastNetworkId " + mLastNetworkId);
2112         pw.println("mLastSubId " + mLastSubId);
2113         pw.println("mLastSimBasedConnectionCarrierName " + mLastSimBasedConnectionCarrierName);
2114         pw.println("mSuspendOptimizationsEnabled " + mContext.getResources().getBoolean(
2115                 R.bool.config_wifiSuspendOptimizationsEnabled));
2116         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2117         pw.println("mPowerSaveDisableRequests " + mPowerSaveDisableRequests);
2118         dumpIpClient(fd, pw, args);
2119         pw.println("WifiScoreReport:");
2120         mWifiScoreReport.dump(fd, pw, args);
2121         pw.println("QosPolicyRequestHandler:");
2122         mQosPolicyRequestHandler.dump(fd, pw, args);
2123         pw.println();
2124     }
2125 
2126     /**
2127      * ******************************************************
2128      * Internal private functions
2129      * ******************************************************
2130      */
2131 
logStateAndMessage(Message message, State state)2132     private void logStateAndMessage(Message message, State state) {
2133         mMessageHandlingStatus = 0;
2134         if (mVerboseLoggingEnabled) {
2135             logd(" " + state.getClass().getSimpleName() + " " + getLogRecString(message));
2136         }
2137     }
2138 
2139     @Override
recordLogRec(Message msg)2140     protected boolean recordLogRec(Message msg) {
2141         switch (msg.what) {
2142             case CMD_RSSI_POLL:
2143                 return mVerboseLoggingEnabled;
2144             default:
2145                 return true;
2146         }
2147     }
2148 
2149     /**
2150      * Return the additional string to be logged by LogRec, default
2151      *
2152      * @param msg that was processed
2153      * @return information to be logged as a String
2154      */
2155     @Override
getLogRecString(Message msg)2156     protected String getLogRecString(Message msg) {
2157         WifiConfiguration config;
2158         Long now;
2159         String report;
2160         String key;
2161         StringBuilder sb = new StringBuilder();
2162         sb.append("screen=").append(mScreenOn ? "on" : "off");
2163         if (mMessageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
2164             sb.append("(").append(mMessageHandlingStatus).append(")");
2165         }
2166         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
2167             sb.append(" uid=" + msg.sendingUid);
2168         }
2169         switch (msg.what) {
2170             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2171                 sb.append(" ");
2172                 sb.append(Integer.toString(msg.arg1));
2173                 sb.append(" ");
2174                 sb.append(Integer.toString(msg.arg2));
2175                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
2176                 if (stateChangeResult != null) {
2177                     sb.append(stateChangeResult.toString());
2178                 }
2179                 break;
2180             case CMD_CONNECT_NETWORK:
2181             case CMD_SAVE_NETWORK: {
2182                 ConnectNetworkMessage cnm = (ConnectNetworkMessage) msg.obj;
2183                 sb.append(" ");
2184                 sb.append(cnm.result.getNetworkId());
2185                 config = mWifiConfigManager.getConfiguredNetwork(cnm.result.getNetworkId());
2186                 if (config != null) {
2187                     sb.append(" ").append(config.getProfileKey());
2188                     sb.append(" nid=").append(config.networkId);
2189                     if (config.hiddenSSID) {
2190                         sb.append(" hidden");
2191                     }
2192                     if (config.preSharedKey != null
2193                             && !config.preSharedKey.equals("*")) {
2194                         sb.append(" hasPSK");
2195                     }
2196                     if (config.ephemeral) {
2197                         sb.append(" ephemeral");
2198                     }
2199                     sb.append(" cuid=").append(config.creatorUid);
2200                     sb.append(" suid=").append(config.lastUpdateUid);
2201                 }
2202                 break;
2203             }
2204             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2205                 if (msg.obj != null) {
2206                     sb.append(" ").append((AssocRejectEventInfo) msg.obj);
2207                 }
2208                 break;
2209             case WifiMonitor.NETWORK_CONNECTION_EVENT: {
2210                 NetworkConnectionEventInfo connectionInfo = (NetworkConnectionEventInfo) msg.obj;
2211                 sb.append(" ");
2212                 sb.append(connectionInfo.networkId);
2213                 sb.append(" ");
2214                 sb.append(connectionInfo.isFilsConnection);
2215                 sb.append(" ").append(mLastBssid);
2216                 sb.append(" nid=").append(mLastNetworkId);
2217                 config = getConnectedWifiConfigurationInternal();
2218                 if (config != null) {
2219                     sb.append(" ").append(config.getProfileKey());
2220                 }
2221                 key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2222                 if (key != null) {
2223                     sb.append(" last=").append(key);
2224                 }
2225                 break;
2226             }
2227             case WifiMonitor.TARGET_BSSID_EVENT:
2228             case WifiMonitor.ASSOCIATED_BSSID_EVENT:
2229                 sb.append(" ");
2230                 sb.append(Integer.toString(msg.arg1));
2231                 sb.append(" ");
2232                 sb.append(Integer.toString(msg.arg2));
2233                 if (msg.obj != null) {
2234                     sb.append(" BSSID=").append((String) msg.obj);
2235                 }
2236                 if (mTargetBssid != null) {
2237                     sb.append(" Target Bssid=").append(mTargetBssid);
2238                 }
2239                 if (mLastBssid != null) {
2240                     sb.append(" Last Bssid=").append(mLastBssid);
2241                 }
2242                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2243                 break;
2244             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2245                 if (msg.obj != null) {
2246                     sb.append(" ").append((DisconnectEventInfo) msg.obj);
2247                 }
2248                 if (mLastBssid != null) {
2249                     sb.append(" lastbssid=").append(mLastBssid);
2250                 }
2251                 if (mWifiInfo.getFrequency() != -1) {
2252                     sb.append(" freq=").append(mWifiInfo.getFrequency());
2253                     sb.append(" rssi=").append(mWifiInfo.getRssi());
2254                 }
2255                 break;
2256             case CMD_RSSI_POLL:
2257             case CMD_ONESHOT_RSSI_POLL:
2258             case CMD_UNWANTED_NETWORK:
2259                 sb.append(" ");
2260                 sb.append(Integer.toString(msg.arg1));
2261                 sb.append(" ");
2262                 sb.append(Integer.toString(msg.arg2));
2263                 if (mWifiInfo.getSSID() != null) {
2264                     if (mWifiInfo.getSSID() != null) {
2265                         sb.append(" ").append(mWifiInfo.getSSID());
2266                     }
2267                 }
2268                 if (mWifiInfo.getBSSID() != null) {
2269                     sb.append(" ").append(mWifiInfo.getBSSID());
2270                 }
2271                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2272                 sb.append(" f=").append(mWifiInfo.getFrequency());
2273                 sb.append(" sc=").append(mWifiInfo.getScore());
2274                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2275                 sb.append(" tx=").append(
2276                         ((int) (mWifiInfo.getSuccessfulTxPacketsPerSecond() * 10)) / 10.0);
2277                 sb.append(", ").append(
2278                         ((int) (mWifiInfo.getRetriedTxPacketsPerSecond() * 10)) / 10.0);
2279                 sb.append(", ").append(((int) (mWifiInfo.getLostTxPacketsPerSecond() * 10)) / 10.0);
2280                 sb.append(" rx=").append(
2281                         ((int) (mWifiInfo.getSuccessfulRxPacketsPerSecond() * 10)) / 10.0);
2282                 sb.append(" bcn=" + mRunningBeaconCount);
2283                 report = reportOnTime();
2284                 if (report != null) {
2285                     sb.append(" ").append(report);
2286                 }
2287                 sb.append(" score=" + mWifiInfo.getScore());
2288                 break;
2289             case CMD_START_CONNECT:
2290                 sb.append(" ");
2291                 sb.append(Integer.toString(msg.arg1));
2292                 sb.append(" ");
2293                 sb.append(Integer.toString(msg.arg2));
2294                 config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2295                 if (config != null) {
2296                     sb.append(" targetConfigKey=").append(config.getProfileKey());
2297                     sb.append(" BSSID=" + config.BSSID);
2298                 }
2299                 if (mTargetBssid != null) {
2300                     sb.append(" targetBssid=").append(mTargetBssid);
2301                 }
2302                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2303                 config = getConnectedWifiConfigurationInternal();
2304                 if (config != null) {
2305                     sb.append(" currentConfigKey=").append(config.getProfileKey());
2306                 }
2307                 break;
2308             case CMD_START_ROAM:
2309                 sb.append(" ");
2310                 sb.append(Integer.toString(msg.arg1));
2311                 sb.append(" ");
2312                 sb.append(Integer.toString(msg.arg2));
2313                 String bssid = (String) msg.obj;
2314                 sb.append(" bssid=").append(bssid);
2315                 if (mTargetBssid != null) {
2316                     sb.append(" ").append(mTargetBssid);
2317                 }
2318                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2319                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
2320                 break;
2321             case CMD_PRE_DHCP_ACTION:
2322                 sb.append(" ");
2323                 sb.append(Integer.toString(msg.arg1));
2324                 sb.append(" ");
2325                 sb.append(Integer.toString(msg.arg2));
2326                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
2327                 sb.append(",").append(mWifiInfo.txBad);
2328                 sb.append(",").append(mWifiInfo.txRetries);
2329                 break;
2330             case CMD_POST_DHCP_ACTION:
2331                 if (mLinkProperties != null) {
2332                     sb.append(" ");
2333                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2334                 }
2335                 break;
2336             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2337                 sb.append(" ");
2338                 sb.append(Integer.toString(msg.arg1));
2339                 sb.append(" ");
2340                 sb.append(Integer.toString(msg.arg2));
2341                 if (msg.obj != null) {
2342                     NetworkInfo info = (NetworkInfo) msg.obj;
2343                     NetworkInfo.State state = info.getState();
2344                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
2345                     if (state != null) {
2346                         sb.append(" st=").append(state);
2347                     }
2348                     if (detailedState != null) {
2349                         sb.append("/").append(detailedState);
2350                     }
2351                 }
2352                 break;
2353             case CMD_IP_CONFIGURATION_LOST:
2354                 int count = -1;
2355                 WifiConfiguration c = getConnectedWifiConfigurationInternal();
2356                 if (c != null) {
2357                     count = c.getNetworkSelectionStatus().getDisableReasonCounter(
2358                             WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
2359                 }
2360                 sb.append(" ");
2361                 sb.append(Integer.toString(msg.arg1));
2362                 sb.append(" ");
2363                 sb.append(Integer.toString(msg.arg2));
2364                 sb.append(" failures: ");
2365                 sb.append(Integer.toString(count));
2366                 sb.append("/");
2367                 sb.append(Integer.toString(mFacade.getIntegerSetting(
2368                         mContext, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 0)));
2369                 if (mWifiInfo.getBSSID() != null) {
2370                     sb.append(" ").append(mWifiInfo.getBSSID());
2371                 }
2372                 sb.append(" bcn=" + mRunningBeaconCount);
2373                 break;
2374             case CMD_UPDATE_LINKPROPERTIES:
2375                 sb.append(" ");
2376                 sb.append(Integer.toString(msg.arg1));
2377                 sb.append(" ");
2378                 sb.append(Integer.toString(msg.arg2));
2379                 if (mLinkProperties != null) {
2380                     sb.append(" ");
2381                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2382                 }
2383                 break;
2384             case CMD_IP_REACHABILITY_LOST:
2385                 if (msg.obj != null) {
2386                     sb.append(" ").append((String) msg.obj);
2387                 }
2388                 break;
2389             case CMD_IP_REACHABILITY_FAILURE:
2390                 if (msg.obj != null) {
2391                     sb.append(" ").append(/* ReachabilityLossInfoParcelable */ msg.obj);
2392                 }
2393                 break;
2394             case CMD_INSTALL_PACKET_FILTER:
2395                 sb.append(" len=" + ((byte[]) msg.obj).length);
2396                 break;
2397             case CMD_SET_FALLBACK_PACKET_FILTERING:
2398                 sb.append(" enabled=" + (boolean) msg.obj);
2399                 break;
2400             case CMD_SET_MAX_DTIM_MULTIPLIER:
2401                 sb.append(" maximum multiplier=" + msg.arg2);
2402                 break;
2403             case CMD_ROAM_WATCHDOG_TIMER:
2404                 sb.append(" ");
2405                 sb.append(Integer.toString(msg.arg1));
2406                 sb.append(" ");
2407                 sb.append(Integer.toString(msg.arg2));
2408                 sb.append(" cur=").append(mRoamWatchdogCount);
2409                 break;
2410             case CMD_CONNECTING_WATCHDOG_TIMER:
2411                 sb.append(" ");
2412                 sb.append(Integer.toString(msg.arg1));
2413                 sb.append(" ");
2414                 sb.append(Integer.toString(msg.arg2));
2415                 sb.append(" cur=").append(mConnectingWatchdogCount);
2416                 break;
2417             case CMD_IPV4_PROVISIONING_SUCCESS:
2418                 sb.append(" ");
2419                 sb.append(/* DhcpResultsParcelable */ msg.obj);
2420                 break;
2421             case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE:
2422                 BtmFrameData frameData = (BtmFrameData) msg.obj;
2423                 if (frameData != null) {
2424                     sb.append(" ").append(frameData.toString());
2425                 }
2426                 break;
2427             case WifiMonitor.NETWORK_NOT_FOUND_EVENT:
2428                 sb.append(" ssid=" + msg.obj);
2429                 break;
2430             case WifiMonitor.BSS_FREQUENCY_CHANGED_EVENT:
2431                 sb.append(" frequency=" + msg.arg1);
2432                 break;
2433             default:
2434                 sb.append(" ");
2435                 sb.append(Integer.toString(msg.arg1));
2436                 sb.append(" ");
2437                 sb.append(Integer.toString(msg.arg2));
2438                 break;
2439         }
2440 
2441         return sb.toString();
2442     }
2443 
2444     @Override
getWhatToString(int what)2445     protected String getWhatToString(int what) {
2446         switch (what) {
2447             case CMD_ACCEPT_UNVALIDATED:
2448                 return "CMD_ACCEPT_UNVALIDATED";
2449             case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF:
2450                 return "CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF";
2451             case CMD_BLUETOOTH_CONNECTION_STATE_CHANGE:
2452                 return "CMD_BLUETOOTH_CONNECTION_STATE_CHANGE";
2453             case CMD_CONFIG_ND_OFFLOAD:
2454                 return "CMD_CONFIG_ND_OFFLOAD";
2455             case CMD_CONNECTING_WATCHDOG_TIMER:
2456                 return "CMD_CONNECTING_WATCHDOG_TIMER";
2457             case CMD_CONNECT_NETWORK:
2458                 return "CMD_CONNECT_NETWORK";
2459             case CMD_DISCONNECT:
2460                 return "CMD_DISCONNECT";
2461             case CMD_ENABLE_RSSI_POLL:
2462                 return "CMD_ENABLE_RSSI_POLL";
2463             case CMD_INSTALL_PACKET_FILTER:
2464                 return "CMD_INSTALL_PACKET_FILTER";
2465             case CMD_IP_CONFIGURATION_LOST:
2466                 return "CMD_IP_CONFIGURATION_LOST";
2467             case CMD_IP_CONFIGURATION_SUCCESSFUL:
2468                 return "CMD_IP_CONFIGURATION_SUCCESSFUL";
2469             case CMD_IP_REACHABILITY_LOST:
2470                 return "CMD_IP_REACHABILITY_LOST";
2471             case CMD_IP_REACHABILITY_FAILURE:
2472                 return "CMD_IP_REACHABILITY_FAILURE";
2473             case CMD_IPCLIENT_STARTUP_TIMEOUT:
2474                 return "CMD_IPCLIENT_STARTUP_TIMEOUT";
2475             case CMD_IPV4_PROVISIONING_FAILURE:
2476                 return "CMD_IPV4_PROVISIONING_FAILURE";
2477             case CMD_IPV4_PROVISIONING_SUCCESS:
2478                 return "CMD_IPV4_PROVISIONING_SUCCESS";
2479             case CMD_NETWORK_STATUS:
2480                 return "CMD_NETWORK_STATUS";
2481             case CMD_ONESHOT_RSSI_POLL:
2482                 return "CMD_ONESHOT_RSSI_POLL";
2483             case CMD_POST_DHCP_ACTION:
2484                 return "CMD_POST_DHCP_ACTION";
2485             case CMD_PRE_DHCP_ACTION:
2486                 return "CMD_PRE_DHCP_ACTION";
2487             case CMD_PRE_DHCP_ACTION_COMPLETE:
2488                 return "CMD_PRE_DHCP_ACTION_COMPLETE";
2489             case CMD_READ_PACKET_FILTER:
2490                 return "CMD_READ_PACKET_FILTER";
2491             case CMD_REASSOCIATE:
2492                 return "CMD_REASSOCIATE";
2493             case CMD_RECONNECT:
2494                 return "CMD_RECONNECT";
2495             case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF:
2496                 return "CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF";
2497             case CMD_RESET_SIM_NETWORKS:
2498                 return "CMD_RESET_SIM_NETWORKS";
2499             case CMD_ROAM_WATCHDOG_TIMER:
2500                 return "CMD_ROAM_WATCHDOG_TIMER";
2501             case CMD_RSSI_POLL:
2502                 return "CMD_RSSI_POLL";
2503             case CMD_SAVE_NETWORK:
2504                 return "CMD_SAVE_NETWORK";
2505             case CMD_SCREEN_STATE_CHANGED:
2506                 return "CMD_SCREEN_STATE_CHANGED";
2507             case CMD_SET_FALLBACK_PACKET_FILTERING:
2508                 return "CMD_SET_FALLBACK_PACKET_FILTERING";
2509             case CMD_SET_MAX_DTIM_MULTIPLIER:
2510                 return "CMD_SET_MAX_DTIM_MULTIPLIER";
2511             case CMD_SET_SUSPEND_OPT_ENABLED:
2512                 return "CMD_SET_SUSPEND_OPT_ENABLED";
2513             case CMD_START_CONNECT:
2514                 return "CMD_START_CONNECT";
2515             case CMD_START_FILS_CONNECTION:
2516                 return "CMD_START_FILS_CONNECTION";
2517             case CMD_START_IP_PACKET_OFFLOAD:
2518                 return "CMD_START_IP_PACKET_OFFLOAD";
2519             case CMD_START_ROAM:
2520                 return "CMD_START_ROAM";
2521             case CMD_STOP_IP_PACKET_OFFLOAD:
2522                 return "CMD_STOP_IP_PACKET_OFFLOAD";
2523             case CMD_UNWANTED_NETWORK:
2524                 return "CMD_UNWANTED_NETWORK";
2525             case CMD_UPDATE_LINKPROPERTIES:
2526                 return "CMD_UPDATE_LINKPROPERTIES";
2527             case CMD_IPCLIENT_CREATED:
2528                 return "CMD_IPCLIENT_CREATED";
2529             case CMD_ACCEPT_EAP_SERVER_CERTIFICATE:
2530                 return "CMD_ACCEPT_EAP_SERVER_CERTIFICATE";
2531             case CMD_REJECT_EAP_INSECURE_CONNECTION:
2532                 return "CMD_REJECT_EAP_SERVER_CERTIFICATE";
2533             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2534                 return "SUPPLICANT_STATE_CHANGE_EVENT";
2535             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2536                 return "AUTHENTICATION_FAILURE_EVENT";
2537             case WifiMonitor.SUP_REQUEST_IDENTITY:
2538                 return "SUP_REQUEST_IDENTITY";
2539             case WifiMonitor.NETWORK_CONNECTION_EVENT:
2540                 return "NETWORK_CONNECTION_EVENT";
2541             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2542                 return "NETWORK_DISCONNECTION_EVENT";
2543             case WifiMonitor.ASSOCIATED_BSSID_EVENT:
2544                 return "ASSOCIATED_BSSID_EVENT";
2545             case WifiMonitor.TARGET_BSSID_EVENT:
2546                 return "TARGET_BSSID_EVENT";
2547             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2548                 return "ASSOCIATION_REJECTION_EVENT";
2549             case WifiMonitor.ANQP_DONE_EVENT:
2550                 return "ANQP_DONE_EVENT";
2551             case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
2552                 return "RX_HS20_ANQP_ICON_EVENT";
2553             case WifiMonitor.GAS_QUERY_DONE_EVENT:
2554                 return "GAS_QUERY_DONE_EVENT";
2555             case WifiMonitor.HS20_REMEDIATION_EVENT:
2556                 return "HS20_REMEDIATION_EVENT";
2557             case WifiMonitor.HS20_DEAUTH_IMMINENT_EVENT:
2558                 return "HS20_DEAUTH_IMMINENT_EVENT";
2559             case WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT:
2560                 return "HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT";
2561             case WifiMonitor.GAS_QUERY_START_EVENT:
2562                 return "GAS_QUERY_START_EVENT";
2563             case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE:
2564                 return "MBO_OCE_BSS_TM_HANDLING_DONE";
2565             case WifiMonitor.TRANSITION_DISABLE_INDICATION:
2566                 return "TRANSITION_DISABLE_INDICATION";
2567             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
2568                 return "GROUP_CREATING_TIMED_OUT";
2569             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2570                 return "P2P_CONNECTION_CHANGED";
2571             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
2572                 return "DISCONNECT_WIFI_REQUEST";
2573             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
2574                 return "DISCONNECT_WIFI_RESPONSE";
2575             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
2576                 return "SET_MIRACAST_MODE";
2577             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
2578                 return "BLOCK_DISCOVERY";
2579             case WifiMonitor.NETWORK_NOT_FOUND_EVENT:
2580                 return "NETWORK_NOT_FOUND_EVENT";
2581             case WifiMonitor.TOFU_CERTIFICATE_EVENT:
2582                 return "TOFU_CERTIFICATE_EVENT";
2583             case WifiMonitor.BSS_FREQUENCY_CHANGED_EVENT:
2584                 return "BSS_FREQUENCY_CHANGED_EVENT";
2585             case RunnerState.STATE_ENTER_CMD:
2586                 return "Enter";
2587             case RunnerState.STATE_EXIT_CMD:
2588                 return "Exit";
2589             default:
2590                 return "what:" + what;
2591         }
2592     }
2593 
2594     /** Check whether this connection is the primary connection on the device. */
isPrimary()2595     private boolean isPrimary() {
2596         return mClientModeManager.getRole() == ROLE_CLIENT_PRIMARY;
2597     }
2598 
isScanOnly()2599     private boolean isScanOnly() {
2600         return mClientModeManager.getRole() == ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
2601     }
2602 
2603     /** Check whether this connection is the secondary internet wifi connection. */
isSecondaryInternet()2604     private boolean isSecondaryInternet() {
2605         return mClientModeManager.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED
2606                 && mClientModeManager.isSecondaryInternet();
2607     }
2608 
2609     /** Check whether this connection is for local only network. */
isLocalOnly()2610     private boolean isLocalOnly() {
2611         return mClientModeManager.getRole() == ROLE_CLIENT_LOCAL_ONLY;
2612     }
2613 
2614     /** Check whether this connection is for local only network due to Ip Provisioning Timeout. */
2615     @Override
isIpProvisioningTimedOut()2616     public boolean isIpProvisioningTimedOut() {
2617         return mIpProvisioningTimedOut;
2618     }
2619 
2620     /**
2621      * Check if originaly requested as local only for ClientModeManager before fallback.
2622      * A secondary role could fallback to primary due to hardware support limit.
2623      * @return true if the original request for ClientModeManager is local only.
2624      */
isRequestedForLocalOnly(WifiConfiguration currentWifiConfiguration, String currentBssid)2625     public boolean isRequestedForLocalOnly(WifiConfiguration currentWifiConfiguration,
2626             String currentBssid) {
2627         Set<Integer> uids =
2628                 mNetworkFactory.getSpecificNetworkRequestUids(
2629                         currentWifiConfiguration, currentBssid);
2630         // Check if there is an active specific request in WifiNetworkFactory for local only.
2631         return !uids.isEmpty();
2632     }
2633 
handleScreenStateChanged(boolean screenOn)2634     private void handleScreenStateChanged(boolean screenOn) {
2635         mScreenOn = screenOn;
2636         if (mVerboseLoggingEnabled) {
2637             logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
2638                     + " mSuspendOptimizationsEnabled="
2639                     + mContext.getResources().getBoolean(
2640                             R.bool.config_wifiSuspendOptimizationsEnabled)
2641                     + " state " + getCurrentState().getName());
2642         }
2643         if (isPrimary() || isSecondaryInternet()) {
2644             // Only enable RSSI polling on primary STA, none of the secondary STA use-cases
2645             // can become the default route when other networks types that provide internet
2646             // connectivity (e.g. cellular) are available. So, no point in scoring
2647             // these connections for the purpose of switching between wifi and other network
2648             // types.
2649             // TODO(b/179518316): Enable this for secondary transient STA also if external scorer
2650             // is in charge of MBB.
2651             enableRssiPolling(screenOn);
2652         }
2653         if (mContext.getResources().getBoolean(R.bool.config_wifiSuspendOptimizationsEnabled)) {
2654             int shouldReleaseWakeLock = 0;
2655             if (screenOn) {
2656                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, shouldReleaseWakeLock);
2657             } else {
2658                 if (isConnected()) {
2659                     // Allow 2s for suspend optimizations to be set
2660                     mSuspendWakeLock.acquire(2000);
2661                     shouldReleaseWakeLock = 1;
2662                 }
2663                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, shouldReleaseWakeLock);
2664             }
2665         }
2666 
2667         if (isConnected()) {
2668             getWifiLinkLayerStats();
2669         }
2670         mOnTimeScreenStateChange = mOnTime;
2671         mLastScreenStateChangeTimeStamp = mLastLinkLayerStatsUpdate;
2672 
2673         if (mVerboseLoggingEnabled) log("handleScreenStateChanged Exit: " + screenOn);
2674     }
2675 
setSuspendOptimizationsNative(int reason, boolean enabled)2676     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
2677         if (mVerboseLoggingEnabled) {
2678             log("setSuspendOptimizationsNative: " + reason + " " + enabled
2679                     + " -want " + mContext.getResources().getBoolean(
2680                             R.bool.config_wifiSuspendOptimizationsEnabled)
2681                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2682                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2683                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2684                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2685         }
2686         //mWifiNative.setSuspendOptimizations(enabled);
2687 
2688         if (enabled) {
2689             mSuspendOptNeedsDisabled &= ~reason;
2690             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
2691             if (mSuspendOptNeedsDisabled == 0
2692                     && mContext.getResources().getBoolean(
2693                             R.bool.config_wifiSuspendOptimizationsEnabled)) {
2694                 if (mVerboseLoggingEnabled) {
2695                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
2696                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2697                             + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2698                             + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2699                             + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2700                 }
2701                 mWifiNative.setSuspendOptimizations(mInterfaceName, true);
2702             }
2703         } else {
2704             mSuspendOptNeedsDisabled |= reason;
2705             mWifiNative.setSuspendOptimizations(mInterfaceName, false);
2706         }
2707     }
2708 
2709     /**
2710      * Makes a record of the user intent about suspend optimizations.
2711      */
setSuspendOptimizations(int reason, boolean enabled)2712     private void setSuspendOptimizations(int reason, boolean enabled) {
2713         if (mVerboseLoggingEnabled) log("setSuspendOptimizations: " + reason + " " + enabled);
2714         if (enabled) {
2715             mSuspendOptNeedsDisabled &= ~reason;
2716         } else {
2717             mSuspendOptNeedsDisabled |= reason;
2718         }
2719         if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2720     }
2721 
updateMloLinkFromPollResults(MloLink link, WifiSignalPollResults pollResults)2722     private void updateMloLinkFromPollResults(MloLink link, WifiSignalPollResults pollResults) {
2723         if (link == null) return;
2724         int linkId = link.getLinkId();
2725         int rssi = RssiUtil.calculateAdjustedRssi(pollResults.getRssi(linkId));
2726         if (rssi > WifiInfo.INVALID_RSSI) {
2727             link.setRssi(rssi);
2728         }
2729         link.setTxLinkSpeedMbps(pollResults.getTxLinkSpeed(linkId));
2730         link.setRxLinkSpeedMbps(pollResults.getRxLinkSpeed(linkId));
2731         link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported(
2732                 pollResults.getFrequency(linkId)));
2733         link.setBand(ScanResult.toBand(pollResults.getFrequency(linkId)));
2734         if (mVerboseLoggingEnabled) {
2735             logd("updateMloLinkFromPollResults: linkId=" + linkId + " rssi=" + link.getRssi()
2736                     + " channel=" + link.getChannel()
2737                     + " band=" + link.getBand()
2738                     + " TxLinkspeed=" + link.getTxLinkSpeedMbps()
2739                     + " RxLinkSpeed=" + link.getRxLinkSpeedMbps());
2740 
2741         }
2742     }
2743 
updateMloLinkFromScanResult(MloLink link)2744     private void updateMloLinkFromScanResult(MloLink link) {
2745         if (link == null || link.getApMacAddress() == null) return;
2746         ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
2747                 mWifiInfo.getNetworkId());
2748         if (scanDetailCache == null) return;
2749         ScanResult matchingScanResult = scanDetailCache.getScanResult(
2750                 link.getApMacAddress().toString());
2751         if (matchingScanResult == null) return;
2752         link.setRssi(matchingScanResult.level);
2753         if (mVerboseLoggingEnabled) {
2754             logd("updateMloLinkFromScanResult: linkId=" + link.getLinkId() + " rssi="
2755                     + link.getRssi());
2756         }
2757     }
2758 
2759     /*
2760      * Fetch link layer stats, RSSI, linkspeed, and frequency on current connection
2761      * and update Network capabilities
2762      */
updateLinkLayerStatsRssiSpeedFrequencyCapabilities(long txBytes, long rxBytes)2763     private WifiLinkLayerStats updateLinkLayerStatsRssiSpeedFrequencyCapabilities(long txBytes,
2764             long rxBytes) {
2765         WifiLinkLayerStats stats = getWifiLinkLayerStats();
2766         WifiSignalPollResults pollResults = mWifiNative.signalPoll(mInterfaceName);
2767         if (pollResults == null) {
2768             return stats;
2769         }
2770 
2771         int newRssi = RssiUtil.calculateAdjustedRssi(pollResults.getRssi());
2772         int newTxLinkSpeed = pollResults.getTxLinkSpeed();
2773         int newFrequency = pollResults.getFrequency();
2774         int newRxLinkSpeed = pollResults.getRxLinkSpeed();
2775         boolean updateNetworkCapabilities = false;
2776 
2777         if (mVerboseLoggingEnabled) {
2778             logd("updateLinkLayerStatsRssiSpeedFrequencyCapabilities rssi=" + newRssi
2779                     + " TxLinkspeed=" + newTxLinkSpeed + " freq=" + newFrequency
2780                     + " RxLinkSpeed=" + newRxLinkSpeed);
2781         }
2782 
2783         for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) {
2784             if (pollResults.isAvailable(link.getLinkId())
2785                     && (link.getState() == MloLink.MLO_LINK_STATE_IDLE
2786                     || link.getState() == MloLink.MLO_LINK_STATE_ACTIVE)) {
2787                 updateMloLinkFromPollResults(link, pollResults);
2788             } else {
2789                 updateMloLinkFromScanResult(link);
2790             }
2791         }
2792 
2793         /*
2794          * set Tx link speed only if it is valid
2795          */
2796         if (newTxLinkSpeed > 0) {
2797             if (newTxLinkSpeed != mWifiInfo.getTxLinkSpeedMbps() && SdkLevel.isAtLeastV()) {
2798                 updateNetworkCapabilities = true;
2799             }
2800             mWifiInfo.setLinkSpeed(newTxLinkSpeed);
2801             mWifiInfo.setTxLinkSpeedMbps(newTxLinkSpeed);
2802         }
2803         /*
2804          * set Rx link speed only if it is valid
2805          */
2806         if (newRxLinkSpeed > 0) {
2807             if (newRxLinkSpeed != mWifiInfo.getRxLinkSpeedMbps() && SdkLevel.isAtLeastV()) {
2808                 updateNetworkCapabilities = true;
2809             }
2810             mWifiInfo.setRxLinkSpeedMbps(newRxLinkSpeed);
2811         }
2812         if (newFrequency > 0) {
2813             if (mWifiInfo.getFrequency() != newFrequency) {
2814                 updateNetworkCapabilities = true;
2815             }
2816             mWifiInfo.setFrequency(newFrequency);
2817         }
2818 
2819         // updateLinkBandwidth() requires the latest frequency information
2820         if (newRssi > WifiInfo.INVALID_RSSI) {
2821             int oldRssi = mWifiInfo.getRssi();
2822             mWifiInfo.setRssi(newRssi);
2823             /*
2824              * Rather than sending the raw RSSI out every time it
2825              * changes, we precalculate the signal level that would
2826              * be displayed in the status bar, and only send the
2827              * broadcast if that much more coarse-grained number
2828              * changes. This cuts down greatly on the number of
2829              * broadcasts, at the cost of not informing others
2830              * interested in RSSI of all the changes in signal
2831              * level.
2832              */
2833             int newSignalLevel = RssiUtil.calculateSignalLevel(mContext, newRssi);
2834             if (newSignalLevel != mLastSignalLevel) {
2835                 sendRssiChangeBroadcast(newRssi);
2836                 updateNetworkCapabilities = true;
2837             } else if (newRssi != oldRssi
2838                     && mWifiGlobals.getVerboseLoggingLevel()
2839                     != WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED) {
2840                 // Send the raw RSSI if verbose logging is enabled by the user so we can show
2841                 // granular RSSI changes in Settings.
2842                 sendRssiChangeBroadcast(newRssi);
2843             }
2844             updateLinkBandwidthAndCapabilities(stats, updateNetworkCapabilities, txBytes,
2845                     rxBytes);
2846             mLastSignalLevel = newSignalLevel;
2847         }
2848         mWifiConfigManager.updateScanDetailCacheFromWifiInfo(mWifiInfo);
2849         /*
2850          * Increment various performance metrics
2851          */
2852         mWifiMetrics.handlePollResult(mInterfaceName, mWifiInfo);
2853         updateCurrentConnectionInfo();
2854         return stats;
2855     }
2856 
2857     // Update the link bandwidth. Also update network capabilities if the link bandwidth changes
2858     // by a large amount or there is a change in signal level or frequency.
updateLinkBandwidthAndCapabilities(WifiLinkLayerStats stats, boolean updateNetworkCapabilities, long txBytes, long rxBytes)2859     private void updateLinkBandwidthAndCapabilities(WifiLinkLayerStats stats,
2860             boolean updateNetworkCapabilities, long txBytes, long rxBytes) {
2861         WifiScoreCard.PerNetwork network = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
2862         network.updateLinkBandwidth(mLastLinkLayerStats, stats, mWifiInfo, txBytes, rxBytes);
2863         int newTxKbps = network.getTxLinkBandwidthKbps();
2864         int newRxKbps = network.getRxLinkBandwidthKbps();
2865         int txDeltaKbps = Math.abs(newTxKbps - mLastTxKbps);
2866         int rxDeltaKbps = Math.abs(newRxKbps - mLastRxKbps);
2867         int bwUpdateThresholdPercent = mContext.getResources().getInteger(
2868                 R.integer.config_wifiLinkBandwidthUpdateThresholdPercent);
2869         if ((txDeltaKbps * 100  >  bwUpdateThresholdPercent * mLastTxKbps)
2870                 || (rxDeltaKbps * 100  >  bwUpdateThresholdPercent * mLastRxKbps)
2871                 || updateNetworkCapabilities) {
2872             mLastTxKbps = newTxKbps;
2873             mLastRxKbps = newRxKbps;
2874             updateCapabilities();
2875         }
2876 
2877         int l2TxKbps = mWifiDataStall.getTxThroughputKbps();
2878         int l2RxKbps = mWifiDataStall.getRxThroughputKbps();
2879         if (l2RxKbps < 0 && l2TxKbps > 0) {
2880             l2RxKbps = l2TxKbps;
2881         }
2882         int [] reportedKbps = {mLastTxKbps, mLastRxKbps};
2883         int [] l2Kbps = {l2TxKbps, l2RxKbps};
2884         network.updateBwMetrics(reportedKbps, l2Kbps);
2885     }
2886 
2887     // Polling has completed, hence we won't have a score anymore
cleanWifiScore()2888     private void cleanWifiScore() {
2889         mWifiInfo.setLostTxPacketsPerSecond(0);
2890         mWifiInfo.setSuccessfulTxPacketsPerSecond(0);
2891         mWifiInfo.setRetriedTxPacketsRate(0);
2892         mWifiInfo.setSuccessfulRxPacketsPerSecond(0);
2893         mWifiScoreReport.reset();
2894         mLastLinkLayerStats = null;
2895         updateCurrentConnectionInfo();
2896     }
2897 
updateLinkProperties(LinkProperties newLp)2898     private void updateLinkProperties(LinkProperties newLp) {
2899         if (mVerboseLoggingEnabled) {
2900             log("Link configuration changed for netId: " + mLastNetworkId
2901                     + " old: " + mLinkProperties + " new: " + newLp);
2902         }
2903         // We own this instance of LinkProperties because IpClient passes us a copy.
2904         mLinkProperties = newLp;
2905 
2906         if (mNetworkAgent != null) {
2907             mNetworkAgent.sendLinkProperties(mLinkProperties);
2908         }
2909 
2910         if (mNetworkAgentState == DetailedState.CONNECTED) {
2911             // If anything has changed and we're already connected, send out a notification.
2912             // TODO: Update all callers to use NetworkCallbacks and delete this.
2913             sendLinkConfigurationChangedBroadcast();
2914         }
2915         if (mVerboseLoggingEnabled) {
2916             StringBuilder sb = new StringBuilder();
2917             sb.append("updateLinkProperties nid: " + mLastNetworkId);
2918             sb.append(" state: " + mNetworkAgentState);
2919 
2920             if (mLinkProperties != null) {
2921                 sb.append(" ");
2922                 sb.append(getLinkPropertiesSummary(mLinkProperties));
2923             }
2924             logd(sb.toString());
2925         }
2926     }
2927 
2928     /**
2929      * Clears all our link properties.
2930      */
clearLinkProperties()2931     private void clearLinkProperties() {
2932         // Clear the link properties obtained from DHCP. The only caller of this
2933         // function has already called IpClient#stop(), which clears its state.
2934         synchronized (mDhcpResultsParcelableLock) {
2935             mDhcpResultsParcelable = new DhcpResultsParcelable();
2936         }
2937 
2938         // Now clear the merged link properties.
2939         mLinkProperties.clear();
2940         if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
2941     }
2942 
2943     // TODO(b/193460475): Remove when tooling supports SystemApi to public API.
2944     @SuppressLint("NewApi")
sendRssiChangeBroadcast(final int newRssi)2945     private void sendRssiChangeBroadcast(final int newRssi) {
2946         mBatteryStatsManager.reportWifiRssiChanged(newRssi);
2947         WifiStatsLog.write(WifiStatsLog.WIFI_SIGNAL_STRENGTH_CHANGED,
2948                 RssiUtil.calculateSignalLevel(mContext, newRssi));
2949 
2950         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
2951         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2952         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
2953         final Bundle opts;
2954         if (SdkLevel.isAtLeastU()) {
2955             opts = BroadcastOptions.makeBasic()
2956                     .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
2957                     .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
2958                     .toBundle();
2959         } else {
2960             opts = null;
2961         }
2962         mBroadcastQueue.queueOrSendBroadcast(
2963                 mClientModeManager,
2964                 () -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
2965                         android.Manifest.permission.ACCESS_WIFI_STATE, opts));
2966     }
2967 
sendLinkConfigurationChangedBroadcast()2968     private void sendLinkConfigurationChangedBroadcast() {
2969         Intent intent = new Intent(WifiManager.ACTION_LINK_CONFIGURATION_CHANGED);
2970         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2971         String summary = "broadcast=ACTION_LINK_CONFIGURATION_CHANGED";
2972         if (mVerboseLoggingEnabled) Log.d(getTag(), "Queuing " + summary);
2973         mBroadcastQueue.queueOrSendBroadcast(
2974                 mClientModeManager,
2975                 () -> {
2976                     if (mVerboseLoggingEnabled) Log.d(getTag(), "Sending " + summary);
2977                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2978                 });
2979     }
2980 
2981     /**
2982      * Helper method used to send state about supplicant - This is NOT information about the current
2983      * wifi connection state.
2984      *
2985      * TODO: b/79504296 This broadcast has been deprecated and should be removed
2986      */
sendSupplicantConnectionChangedBroadcast(boolean connected)2987     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
2988         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
2989         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2990         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
2991         String summary = "broadcast=SUPPLICANT_CONNECTION_CHANGE_ACTION"
2992                 + " EXTRA_SUPPLICANT_CONNECTED=" + connected;
2993         if (mVerboseLoggingEnabled) Log.d(getTag(), "Queuing " + summary);
2994         mBroadcastQueue.queueOrSendBroadcast(
2995                 mClientModeManager,
2996                 () -> {
2997                     if (mVerboseLoggingEnabled) Log.d(getTag(), "Sending " + summary);
2998                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2999                 });
3000     }
3001 
3002     /**
3003      * Record the detailed state of a network.
3004      *
3005      * @param state the new {@code DetailedState}
3006      */
sendNetworkChangeBroadcast(NetworkInfo.DetailedState state)3007     private void sendNetworkChangeBroadcast(NetworkInfo.DetailedState state) {
3008         boolean hidden = false;
3009 
3010         if (mIsAutoRoaming) {
3011             // There is generally a confusion in the system about colluding
3012             // WiFi Layer 2 state (as reported by supplicant) and the Network state
3013             // which leads to multiple confusion.
3014             //
3015             // If link is roaming, we already have an IP address
3016             // as well we were connected and are doing L2 cycles of
3017             // reconnecting or renewing IP address to check that we still have it
3018             // This L2 link flapping should not be reflected into the Network state
3019             // which is the state of the WiFi Network visible to Layer 3 and applications
3020             // Note that once roaming is completed, we will
3021             // set the Network state to where it should be, or leave it as unchanged
3022             //
3023             hidden = true;
3024         }
3025         if (mVerboseLoggingEnabled) {
3026             log("sendNetworkChangeBroadcast"
3027                     + " oldState=" + mNetworkAgentState
3028                     + " newState=" + state
3029                     + " hidden=" + hidden);
3030         }
3031         if (hidden || state == mNetworkAgentState) return;
3032         mNetworkAgentState = state;
3033         sendNetworkChangeBroadcastWithCurrentState();
3034     }
3035 
getNetworkStateListenerCmmRole()3036     private int getNetworkStateListenerCmmRole() {
3037         if (isPrimary() || isScanOnly()) {
3038             // Wifi disconnect could be received in ScanOnlyMode when wifi scanning is enabled since
3039             // the mode switch happens before the disconnect actually happens. Therefore, treat
3040             // the scan only mode the same as primary since only the primary is allowed to change
3041             // into scan only mode.
3042             return WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY;
3043         }
3044         if (isSecondaryInternet()) {
3045             return WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_SECONDARY_INTERNET;
3046         }
3047         if (isLocalOnly()) {
3048             return WifiManager.WifiNetworkStateChangedListener
3049                     .WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY;
3050         }
3051         return -1;
3052     }
3053 
convertDetailedStateToNetworkStateChangedCode(DetailedState detailedState)3054     private int convertDetailedStateToNetworkStateChangedCode(DetailedState detailedState) {
3055         switch (detailedState) {
3056             case IDLE:
3057                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_IDLE;
3058             case SCANNING:
3059                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_SCANNING;
3060             case CONNECTING:
3061                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_CONNECTING;
3062             case AUTHENTICATING:
3063                 return WifiManager.WifiNetworkStateChangedListener
3064                         .WIFI_NETWORK_STATUS_AUTHENTICATING;
3065             case OBTAINING_IPADDR:
3066                 return WifiManager.WifiNetworkStateChangedListener
3067                         .WIFI_NETWORK_STATUS_OBTAINING_IPADDR;
3068             case CONNECTED:
3069                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_CONNECTED;
3070             case DISCONNECTED:
3071                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_DISCONNECTED;
3072             case FAILED:
3073                 return WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_FAILED;
3074             default:
3075                 // There are some DetailedState codes that are not being used in wifi, so ignore
3076                 // them.
3077                 return -1;
3078         }
3079     }
3080 
sendNetworkChangeBroadcastWithCurrentState()3081     private void sendNetworkChangeBroadcastWithCurrentState() {
3082         // copy into local variables to force lambda to capture by value and not reference, since
3083         // mNetworkAgentState is mutable and can change
3084         final DetailedState networkAgentState = mNetworkAgentState;
3085         if (mVerboseLoggingEnabled) {
3086             Log.d(getTag(), "Queueing broadcast=NETWORK_STATE_CHANGED_ACTION"
3087                     + " networkAgentState=" + networkAgentState);
3088         }
3089         int networkStateChangedCmmRole = getNetworkStateListenerCmmRole();
3090         int networkStateChangedState = convertDetailedStateToNetworkStateChangedCode(
3091                 networkAgentState);
3092         if (networkStateChangedCmmRole != -1 && networkStateChangedState != -1) {
3093             mWifiInjector.getActiveModeWarden().onNetworkStateChanged(
3094                     networkStateChangedCmmRole, networkStateChangedState);
3095         }
3096         mBroadcastQueue.queueOrSendBroadcast(
3097                 mClientModeManager,
3098                 () -> sendNetworkChangeBroadcast(
3099                         mContext, networkAgentState, mVerboseLoggingEnabled));
3100     }
3101 
3102     /** Send a NETWORK_STATE_CHANGED_ACTION broadcast. */
sendNetworkChangeBroadcast( Context context, DetailedState networkAgentState, boolean verboseLoggingEnabled)3103     public static void sendNetworkChangeBroadcast(
3104             Context context, DetailedState networkAgentState, boolean verboseLoggingEnabled) {
3105         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
3106         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3107         NetworkInfo networkInfo = makeNetworkInfo(networkAgentState);
3108         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
3109         if (verboseLoggingEnabled) {
3110             Log.d(TAG, "Sending broadcast=NETWORK_STATE_CHANGED_ACTION"
3111                     + " networkAgentState=" + networkAgentState);
3112         }
3113         //TODO(b/69974497) This should be non-sticky, but settings needs fixing first.
3114         if (SdkLevel.isAtLeastU()) {
3115             final Context userAllContext = context.createContextAsUser(
3116                     UserHandle.ALL, 0 /* flags */);
3117             final Bundle opts = BroadcastOptions.makeBasic()
3118                     .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
3119                     .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
3120                     .toBundle();
3121             userAllContext.sendStickyBroadcast(intent, opts);
3122         } else {
3123             context.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3124         }
3125     }
3126 
makeNetworkInfo(DetailedState networkAgentState)3127     private static NetworkInfo makeNetworkInfo(DetailedState networkAgentState) {
3128         final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
3129         ni.setDetailedState(networkAgentState, null, null);
3130         return ni;
3131     }
3132 
findMatchingInfoElements(@ullable String bssid)3133     private List<ScanResult.InformationElement> findMatchingInfoElements(@Nullable String bssid) {
3134         if (bssid == null) return null;
3135         ScanResult matchingScanResult = mScanRequestProxy.getScanResult(bssid);
3136         if (matchingScanResult == null || matchingScanResult.informationElements == null) {
3137             return null;
3138         }
3139         return Arrays.asList(matchingScanResult.informationElements);
3140     }
3141 
setMultiLinkInfoFromScanCache(@ullable String bssid)3142     private void setMultiLinkInfoFromScanCache(@Nullable String bssid) {
3143         if (bssid == null) return;
3144         ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
3145                 mWifiInfo.getNetworkId());
3146         ScanResult matchingScanResult = null;
3147         if (scanDetailCache != null) {
3148             matchingScanResult = scanDetailCache.getScanResult(bssid);
3149         }
3150         /**
3151          * If FW roams to a new AP, the BSSID may not be in the scan detailed cache. Set Multi-Link
3152          * info only if the BSSID is present in the scan detailed cache and AP is a Multi-Link
3153          * Device. If not, clear Multi-Link info from WifiInfo. After association
3154          * {@link ClientModeImpl#updateMloLinkAddrAndStates(ConnectionMloLinksInfo)} will update
3155          * the Multi-Link info from supplicant if present.
3156          */
3157         if (matchingScanResult != null && matchingScanResult.getApMldMacAddress() != null) {
3158             mWifiInfo.setApMldMacAddress(matchingScanResult.getApMldMacAddress());
3159             mWifiInfo.setApMloLinkId(matchingScanResult.getApMloLinkId());
3160             // Deep copy the affiliated links to avoid any overwrite in future from WifiInfo.
3161             List<MloLink> deepCopyAffiliatedMloLinks = new ArrayList<>();
3162             for (MloLink link : matchingScanResult.getAffiliatedMloLinks()) {
3163                 deepCopyAffiliatedMloLinks.add(new MloLink(link, NetworkCapabilities.REDACT_NONE));
3164             }
3165             mWifiInfo.setAffiliatedMloLinks(deepCopyAffiliatedMloLinks);
3166         } else {
3167             mWifiInfo.setApMldMacAddress(null);
3168             mWifiInfo.setApMloLinkId(MloLink.INVALID_MLO_LINK_ID);
3169             mWifiInfo.setAffiliatedMloLinks(Collections.emptyList());
3170         }
3171         updateCurrentConnectionInfo();
3172     }
3173 
3174     /**
3175      * Multi-link info should not be set from scan cache after 'SupplicantState.ASSOCIATED' as it
3176      * overwrites link states collected during ASSOCIATION. Return if multi-link info is settable
3177      * on the current state.
3178      */
isMultiLinkInfoSettableFromScanCache(SupplicantState currentState)3179     private boolean isMultiLinkInfoSettableFromScanCache(SupplicantState currentState) {
3180         return currentState != SupplicantState.FOUR_WAY_HANDSHAKE
3181                 && currentState != SupplicantState.GROUP_HANDSHAKE
3182                 && currentState != SupplicantState.COMPLETED;
3183     }
3184 
3185     // Return true if link frequency is changed.
updateAssociatedMloLinksFromLinksInfoWhenBssFreqChanged(int bssFreq)3186     private boolean updateAssociatedMloLinksFromLinksInfoWhenBssFreqChanged(int bssFreq) {
3187         boolean isLinkFrequencyChanged = false;
3188         // retrieve mlo links info with updated frequencies from HAL
3189         WifiNative.ConnectionMloLinksInfo mloLinksInfo = mWifiNative.getConnectionMloLinksInfo(
3190                 mInterfaceName);
3191         if (mloLinksInfo == null) {
3192             return false;
3193         }
3194         for (int i = 0; i < mloLinksInfo.links.length; i++) {
3195             MloLink link = mWifiInfo.getAffiliatedMloLink(mloLinksInfo.links[i].getLinkId());
3196             if (link != null && mloLinksInfo.links[i].getFrequencyMHz() == bssFreq) {
3197                 int linkCurFreq = ScanResult.convertChannelToFrequencyMhzIfSupported(
3198                         link.getChannel(), link.getBand());
3199                 if (linkCurFreq != ScanResult.UNSPECIFIED && bssFreq != linkCurFreq) {
3200                     if (link.getRssi() == mWifiInfo.getRssi()
3201                             && ScanResult.convertChannelToFrequencyMhzIfSupported(link.getChannel(),
3202                             link.getBand()) == mWifiInfo.getFrequency()) {
3203                         mWifiInfo.setFrequency(bssFreq);
3204                     }
3205                     isLinkFrequencyChanged = true;
3206                     link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported(bssFreq));
3207                     link.setBand(ScanResult.toBand(bssFreq));
3208                     break;
3209                 }
3210             }
3211         }
3212         return isLinkFrequencyChanged;
3213     }
3214 
handleSupplicantStateChange(StateChangeResult stateChangeResult)3215     private SupplicantState handleSupplicantStateChange(StateChangeResult stateChangeResult) {
3216         SupplicantState state = stateChangeResult.state;
3217         mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, state);
3218         // Supplicant state change
3219         // [31-13] Reserved for future use
3220         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
3221         // 50023 supplicant_state_changed (custom|1|5)
3222         mWifiInfo.setSupplicantState(state);
3223         // Network id and SSID are only valid when we start connecting
3224         if (SupplicantState.isConnecting(state)) {
3225             mWifiInfo.setNetworkId(stateChangeResult.networkId);
3226             mWifiInfo.setBSSID(stateChangeResult.bssid);
3227             mWifiInfo.setSSID(stateChangeResult.wifiSsid);
3228             if (stateChangeResult.frequencyMhz > 0) {
3229                 mWifiInfo.setFrequency(stateChangeResult.frequencyMhz);
3230             }
3231             // Multi-link info is set from scan cache (multi-link state: unassociated). On
3232             // association, connection capabilities and multi-link state are queried from
3233             // supplicant and link info is updated. (multi-link state: active/idle). After
3234             // association, don't set the multi-link info from scan cache.
3235             if (isMultiLinkInfoSettableFromScanCache(state)) {
3236                 setMultiLinkInfoFromScanCache(stateChangeResult.bssid);
3237             }
3238             if (state == SupplicantState.ASSOCIATED) {
3239                 updateWifiInfoLinkParamsAfterAssociation();
3240             }
3241             mWifiInfo.setInformationElements(findMatchingInfoElements(stateChangeResult.bssid));
3242         } else {
3243             // Reset parameters according to WifiInfo.reset()
3244             mWifiBlocklistMonitor.removeAffiliatedBssids(mWifiInfo.getBSSID());
3245             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
3246             mWifiInfo.setBSSID(null);
3247             mWifiInfo.setSSID(null);
3248             mWifiInfo.setWifiStandard(ScanResult.WIFI_STANDARD_UNKNOWN);
3249             mWifiInfo.setInformationElements(null);
3250             mWifiInfo.clearCurrentSecurityType();
3251             mWifiInfo.resetMultiLinkInfo();
3252         }
3253 
3254         // SSID might have been updated, so call updateCapabilities
3255         updateCapabilities();
3256 
3257         WifiConfiguration config = getConnectedWifiConfigurationInternal();
3258         if (config == null) {
3259             // If not connected, this should be non-null.
3260             config = getConnectingWifiConfigurationInternal();
3261         }
3262         if (config != null && config.networkId == mWifiInfo.getNetworkId()) {
3263             updateWifiInfoWhenConnected(config);
3264 
3265             // Set meteredHint if scan result says network is expensive
3266             ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
3267                     config.networkId);
3268             if (scanDetailCache != null) {
3269                 ScanDetail scanDetail = scanDetailCache.getScanDetail(stateChangeResult.bssid);
3270                 if (scanDetail != null) {
3271                     mWifiInfo.setFrequency(scanDetail.getScanResult().frequency);
3272                     NetworkDetail networkDetail = scanDetail.getNetworkDetail();
3273                     if (networkDetail != null
3274                             && networkDetail.getAnt() == NetworkDetail.Ant.ChargeablePublic) {
3275                         mWifiInfo.setMeteredHint(true);
3276                     }
3277                 }
3278             }
3279         }
3280         mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
3281         updateCurrentConnectionInfo();
3282         return state;
3283     }
3284 
handleNetworkConnectionEventInfo( WifiConfiguration config, NetworkConnectionEventInfo connectionInfo)3285     private void handleNetworkConnectionEventInfo(
3286             WifiConfiguration config, NetworkConnectionEventInfo connectionInfo) {
3287         if (connectionInfo == null) return;
3288 
3289         mWifiInfo.setBSSID(connectionInfo.bssid);
3290         mWifiInfo.setNetworkId(connectionInfo.networkId);
3291 
3292         if (config != null && connectionInfo.keyMgmtMask != null) {
3293             // Besides allowed key management, pmf and wep keys are necessary to
3294             // identify WPA3 Enterprise and WEP, so the original configuration
3295             // is still necessary.
3296             WifiConfiguration tmp = new WifiConfiguration(config);
3297             SecurityParams securityParams =
3298                     config.getNetworkSelectionStatus().getLastUsedSecurityParams();
3299             tmp.requirePmf = securityParams.isRequirePmf();
3300             tmp.allowedProtocols = securityParams.getAllowedProtocols();
3301             tmp.allowedPairwiseCiphers = securityParams.getAllowedPairwiseCiphers();
3302             tmp.allowedGroupCiphers = securityParams.getAllowedGroupCiphers();
3303             tmp.setSecurityParams(connectionInfo.keyMgmtMask);
3304             mWifiInfo.setCurrentSecurityType(tmp.getDefaultSecurityParams().getSecurityType());
3305             // Update the last used security params.
3306             config.getNetworkSelectionStatus().setLastUsedSecurityParams(
3307                     tmp.getDefaultSecurityParams());
3308             mWifiConfigManager.setNetworkLastUsedSecurityParams(config.networkId,
3309                     tmp.getDefaultSecurityParams());
3310             Log.i(getTag(), "Update current security type to " + mWifiInfo.getCurrentSecurityType()
3311                     + " from network connection event.");
3312         }
3313     }
3314 
updateWifiInfoWhenConnected(@onNull WifiConfiguration config)3315     private void updateWifiInfoWhenConnected(@NonNull WifiConfiguration config) {
3316         mWifiInfo.setEphemeral(config.ephemeral);
3317         mWifiInfo.setTrusted(config.trusted);
3318         mWifiInfo.setOemPaid(config.oemPaid);
3319         mWifiInfo.setOemPrivate(config.oemPrivate);
3320         mWifiInfo.setCarrierMerged(config.carrierMerged);
3321         mWifiInfo.setSubscriptionId(config.subscriptionId);
3322         mWifiInfo.setOsuAp(config.osu);
3323         mWifiInfo.setRestricted(config.restricted);
3324         if (config.fromWifiNetworkSpecifier || config.fromWifiNetworkSuggestion) {
3325             mWifiInfo.setRequestingPackageName(config.creatorName);
3326         }
3327         mWifiInfo.setIsPrimary(isPrimary());
3328         SecurityParams securityParams = config.getNetworkSelectionStatus()
3329                 .getLastUsedSecurityParams();
3330         if (securityParams != null) {
3331             Log.i(getTag(), "Update current security type to " + securityParams.getSecurityType());
3332             mWifiInfo.setCurrentSecurityType(securityParams.getSecurityType());
3333         } else {
3334             mWifiInfo.clearCurrentSecurityType();
3335             Log.e(TAG, "Network connection candidate with no security parameters");
3336         }
3337         updateCurrentConnectionInfo();
3338     }
3339 
3340     /**
3341      * Update mapping of affiliated BSSID in blocklist. Called when there is a change in MLO links.
3342      */
updateBlockListAffiliatedBssids()3343     private void updateBlockListAffiliatedBssids() {
3344         /**
3345          * getAffiliatedMloLinks() returns a list of MloLink objects for all the links
3346          * advertised by AP-MLD including the associated link. Update mWifiBlocklistMonitor
3347          * with all affiliated AP link MAC addresses, excluding the associated link, indexed
3348          * with associated AP link MAC address (BSSID).
3349          * For e.g.
3350          *  link1_bssid -> affiliated {link2_bssid, link3_bssid}
3351          * Above mapping is used to block list all affiliated links when associated link is
3352          * block listed.
3353          */
3354         List<String> affiliatedBssids = new ArrayList<>();
3355         for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) {
3356             if (link.getApMacAddress() != null && !Objects.equals(mWifiInfo.getBSSID(),
3357                     link.getApMacAddress().toString())) {
3358                 affiliatedBssids.add(link.getApMacAddress().toString());
3359             }
3360         }
3361         mWifiBlocklistMonitor.setAffiliatedBssids(mWifiInfo.getBSSID(), affiliatedBssids);
3362     }
3363 
3364     /**
3365      * Clear MLO link states to UNASSOCIATED.
3366      */
clearMloLinkStates()3367     private void clearMloLinkStates() {
3368         for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) {
3369             link.setState(MloLink.MLO_LINK_STATE_UNASSOCIATED);
3370         }
3371     }
3372 
3373     /**
3374      * Update the MLO link states to ACTIVE or IDLE depending on any traffic stream is mapped to the
3375      * link.
3376      *
3377      * @param info MLO link object from HAL.
3378      */
updateMloLinkStates(@ullable WifiNative.ConnectionMloLinksInfo info)3379     private void updateMloLinkStates(@Nullable WifiNative.ConnectionMloLinksInfo info) {
3380         if (info == null) return;
3381         for (int i = 0; i < info.links.length; i++) {
3382             mWifiInfo.updateMloLinkState(info.links[i].getLinkId(),
3383                     info.links[i].isAnyTidMapped() ? MloLink.MLO_LINK_STATE_ACTIVE
3384                             : MloLink.MLO_LINK_STATE_IDLE);
3385         }
3386     }
3387     /**
3388      * Update the MLO link states to ACTIVE or IDLE depending on any traffic stream is mapped to the
3389      * link. Also, update the link MAC address.
3390      *
3391      * @param info MLO link object from HAL.
3392      */
updateMloLinkAddrAndStates(@ullable WifiNative.ConnectionMloLinksInfo info)3393     private void updateMloLinkAddrAndStates(@Nullable WifiNative.ConnectionMloLinksInfo info) {
3394         if (info == null) return;
3395         // At this stage, the expectation is that we already have MLO link information collected
3396         // from scan detailed cache. If the MLO link information is empty, probably FW/driver roamed
3397         // to a new AP which is not in scan detailed cache. Update MLO links with the details
3398         // provided by the supplicant in ConnectionMloLinksInfo. The supplicant provides only the
3399         // associated links.
3400         if (mWifiInfo.getAffiliatedMloLinks().isEmpty()) {
3401             mWifiInfo.setApMldMacAddress(info.apMldMacAddress);
3402             mWifiInfo.setApMloLinkId(info.apMloLinkId);
3403             List<MloLink> affiliatedMloLinks = new ArrayList<>();
3404             for (int i = 0; i < info.links.length; i++) {
3405                 MloLink link = new MloLink();
3406                 link.setLinkId(info.links[i].getLinkId());
3407                 link.setStaMacAddress(info.links[i].getStaMacAddress());
3408                 link.setApMacAddress(info.links[i].getApMacAddress());
3409                 link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported(
3410                         info.links[i].getFrequencyMHz()));
3411                 link.setBand(ScanResult.toBand(info.links[i].getFrequencyMHz()));
3412                 link.setState(info.links[i].isAnyTidMapped() ? MloLink.MLO_LINK_STATE_ACTIVE
3413                         : MloLink.MLO_LINK_STATE_IDLE);
3414                 affiliatedMloLinks.add(link);
3415             }
3416             mWifiInfo.setAffiliatedMloLinks(affiliatedMloLinks);
3417         } else {
3418             for (int i = 0; i < info.links.length; i++) {
3419                 mWifiInfo.updateMloLinkStaAddress(info.links[i].getLinkId(),
3420                         info.links[i].getStaMacAddress());
3421                 mWifiInfo.updateMloLinkState(info.links[i].getLinkId(),
3422                         info.links[i].isAnyTidMapped() ? MloLink.MLO_LINK_STATE_ACTIVE
3423                                 : MloLink.MLO_LINK_STATE_IDLE);
3424             }
3425         }
3426     }
3427 
updateWifiInfoLinkParamsAfterAssociation()3428     private void updateWifiInfoLinkParamsAfterAssociation() {
3429         mLastConnectionCapabilities = mWifiNative.getConnectionCapabilities(mInterfaceName);
3430         int maxTxLinkSpeedMbps = mThroughputPredictor.predictMaxTxThroughput(
3431                 mLastConnectionCapabilities);
3432         int maxRxLinkSpeedMbps = mThroughputPredictor.predictMaxRxThroughput(
3433                 mLastConnectionCapabilities);
3434         mWifiInfo.setWifiStandard(mLastConnectionCapabilities.wifiStandard);
3435         mWifiInfo.setMaxSupportedTxLinkSpeedMbps(maxTxLinkSpeedMbps);
3436         mWifiInfo.setMaxSupportedRxLinkSpeedMbps(maxRxLinkSpeedMbps);
3437         mWifiInfo.enableApTidToLinkMappingNegotiationSupport(
3438                 mLastConnectionCapabilities.apTidToLinkMapNegotiationSupported);
3439         mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(mInterfaceName,
3440                 maxTxLinkSpeedMbps, maxRxLinkSpeedMbps);
3441         mWifiMetrics.setConnectionChannelWidth(mInterfaceName,
3442                 mLastConnectionCapabilities.channelBandwidth);
3443         if (mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11BE) {
3444             updateMloLinkAddrAndStates(mWifiNative.getConnectionMloLinksInfo(mInterfaceName));
3445             updateBlockListAffiliatedBssids();
3446         }
3447         if (SdkLevel.isAtLeastV() && mLastConnectionCapabilities.vendorData != null) {
3448             mWifiInfo.setVendorData(mLastConnectionCapabilities.vendorData);
3449         }
3450         if (mVerboseLoggingEnabled) {
3451             StringBuilder sb = new StringBuilder();
3452             logd(sb.append("WifiStandard: ").append(ScanResult.wifiStandardToString(
3453                             mLastConnectionCapabilities.wifiStandard))
3454                     .append(" maxTxSpeed: ").append(maxTxLinkSpeedMbps)
3455                     .append(" maxRxSpeed: ").append(maxRxLinkSpeedMbps)
3456                     .toString());
3457         }
3458         updateCurrentConnectionInfo();
3459     }
3460 
3461     /**
3462      * Tells IpClient what BSSID, L2Key and GroupHint to use for IpMemoryStore.
3463      */
updateLayer2Information()3464     private void updateLayer2Information() {
3465         if (mIpClient != null) {
3466             Pair<String, String> p = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
3467             if (!p.equals(mLastL2KeyAndGroupHint)) {
3468                 final MacAddress currentBssid =
3469                         NativeUtil.getMacAddressOrNull(mWifiInfo.getBSSID());
3470                 final Layer2Information l2Information = new Layer2Information(
3471                         p.first, p.second, currentBssid);
3472                 // Update current BSSID on IpClient side whenever l2Key and groupHint
3473                 // pair changes (i.e. the initial connection establishment or L2 roaming
3474                 // happened). If we have COMPLETED the roaming to a different BSSID, start
3475                 // doing DNAv4/DNAv6 -style probing for on-link neighbors of interest (e.g.
3476                 // routers/DNS servers/default gateway).
3477                 if (mIpClient.updateLayer2Information(l2Information)) {
3478                     mLastL2KeyAndGroupHint = p;
3479                 } else {
3480                     mLastL2KeyAndGroupHint = null;
3481                 }
3482             }
3483         }
3484     }
3485     private @Nullable Pair<String, String> mLastL2KeyAndGroupHint = null;
3486 
3487     /**
3488      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
3489      * using the interface, stopping DHCP & disabling interface
3490      *
3491      * @param disconnectReason must be one of WifiDisconnectReported.FailureReason values
3492      *                         defined in /frameworks/proto_logging/stats/atoms.proto
3493      */
handleNetworkDisconnect(boolean newConnectionInProgress, int disconnectReason)3494     private void handleNetworkDisconnect(boolean newConnectionInProgress, int disconnectReason) {
3495         if (newConnectionInProgress) {
3496             mFrameworkDisconnectReasonOverride = mIsUserSelected
3497                     ? WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NEW_CONNECTION_USER
3498                     : WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NEW_CONNECTION_OTHERS;
3499         }
3500         int wifiStatsLogDisconnectReason = mFrameworkDisconnectReasonOverride != 0
3501                 ? mFrameworkDisconnectReasonOverride : disconnectReason;
3502         mFrameworkDisconnectReasonOverride = 0;
3503         mWifiMetrics.reportNetworkDisconnect(mInterfaceName, wifiStatsLogDisconnectReason,
3504                 mWifiInfo.getRssi(),
3505                 mWifiInfo.getLinkSpeed(),
3506                 mWifiInfo.getLastRssiUpdateMillis());
3507 
3508         if (mVerboseLoggingEnabled) {
3509             Log.v(getTag(), "handleNetworkDisconnect: newConnectionInProgress: "
3510                     + newConnectionInProgress, new Throwable());
3511         }
3512 
3513         if (isPrimary()) {
3514             WifiConfiguration wifiConfig = getConnectedWifiConfigurationInternal();
3515             if (wifiConfig != null) {
3516                 ScanResultMatchInfo matchInfo =
3517                         ScanResultMatchInfo.fromWifiConfiguration(wifiConfig);
3518                 // WakeupController should only care about the primary, internet providing network
3519                 mWakeupController.setLastDisconnectInfo(matchInfo);
3520             }
3521             mRssiMonitor.reset();
3522             // On disconnect, restore roaming mode to normal
3523             if (!newConnectionInProgress) {
3524                 enableRoaming(true);
3525             }
3526         }
3527 
3528         clearTargetBssid("handleNetworkDisconnect");
3529 
3530         // Don't stop DHCP if Fils connection is in progress.
3531         if (newConnectionInProgress && mIpClientWithPreConnection) {
3532             if (mVerboseLoggingEnabled) {
3533                 log("handleNetworkDisconnect: Don't stop IpClient as fils connection in progress: "
3534                         + " mLastNetworkId: " + mLastNetworkId
3535                         + " mTargetNetworkId" + mTargetNetworkId);
3536             }
3537         } else {
3538             stopDhcpSetup();
3539         }
3540 
3541         // DISASSOC_AP_BUSY could be received in both after L3 connection is successful or right
3542         // after BSSID association if the AP can't accept more stations.
3543         if (disconnectReason == StaIfaceReasonCode.DISASSOC_AP_BUSY) {
3544             mWifiConfigManager.setRecentFailureAssociationStatus(
3545                     mWifiInfo.getNetworkId(),
3546                     WifiConfiguration.RECENT_FAILURE_DISCONNECTION_AP_BUSY);
3547             // Block the current BSS temporarily since it cannot handle more stations
3548             WifiConfiguration config = getConnectedWifiConfigurationInternal();
3549             if (config == null) {
3550                 config = getConnectingWifiConfigurationInternal();
3551             }
3552             mWifiBlocklistMonitor.blockBssidForDurationMs(mLastBssid, config,
3553                     DISASSOC_AP_BUSY_DISABLE_DURATION_MS,
3554                     WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA, mWifiInfo.getRssi());
3555         }
3556 
3557         mWifiScoreReport.stopConnectedNetworkScorer();
3558         /* Reset data structures */
3559         mWifiScoreReport.reset();
3560         mWifiBlocklistMonitor.removeAffiliatedBssids(mWifiInfo.getBSSID());
3561         mWifiInfo.reset();
3562         /* Reset roaming parameters */
3563         mIsAutoRoaming = false;
3564 
3565         sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
3566         if (mNetworkAgent != null) {
3567             mNetworkAgent.unregister();
3568             mNetworkAgent = null;
3569             mQosPolicyRequestHandler.setNetworkAgent(null);
3570         }
3571 
3572         /* Clear network properties */
3573         clearLinkProperties();
3574 
3575         mLastBssid = null;
3576         mIpProvisioningTimedOut = false;
3577         mLastLinkLayerStats = null;
3578         registerDisconnected();
3579         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
3580         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
3581         mCurrentConnectionDetectedCaptivePortal = false;
3582         mCurrentConnectionReportedCertificateExpired = false;
3583         mLastSimBasedConnectionCarrierName = null;
3584         mNudFailureCounter = new Pair<>(0L, 0);
3585         checkAbnormalDisconnectionAndTakeBugReport();
3586         mWifiScoreCard.resetConnectionState(mInterfaceName);
3587         updateLayer2Information();
3588         // If there is new connection in progress, this is for the new connection, so keept it.
3589         if (!newConnectionInProgress) {
3590             mIsUserSelected = false;
3591         }
3592         updateCurrentConnectionInfo();
3593     }
3594 
handlePreDhcpSetup()3595     void handlePreDhcpSetup() {
3596         if (!mWifiGlobals.isBluetoothConnected()) {
3597             /*
3598              * There are problems setting the Wi-Fi driver's power
3599              * mode to active when bluetooth coexistence mode is
3600              * enabled or sense.
3601              * <p>
3602              * We set Wi-Fi to active mode when
3603              * obtaining an IP address because we've found
3604              * compatibility issues with some routers with low power
3605              * mode.
3606              * <p>
3607              * In order for this active power mode to properly be set,
3608              * we disable coexistence mode until we're done with
3609              * obtaining an IP address.  One exception is if we
3610              * are currently connected to a headset, since disabling
3611              * coexistence would interrupt that connection.
3612              */
3613             // Disable the coexistence mode
3614             mWifiNative.setBluetoothCoexistenceMode(
3615                     mInterfaceName, WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
3616         }
3617 
3618         // Disable power save and suspend optimizations during DHCP
3619         // Note: The order here is important for now. Brcm driver changes
3620         // power settings when we control suspend mode optimizations.
3621         // TODO: Remove this comment when the driver is fixed.
3622         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
3623         setPowerSave(POWER_SAVE_CLIENT_DHCP, false);
3624 
3625         // Update link layer stats
3626         getWifiLinkLayerStats();
3627 
3628         if (mWifiP2pConnection.isConnected() && !mWifiP2pConnection.isP2pInWaitingState()) {
3629             // P2P discovery breaks DHCP, so shut it down in order to get through this.
3630             // Once P2P service receives this message and processes it accordingly, it is supposed
3631             // to send arg2 (i.e. CMD_PRE_DHCP_ACTION_COMPLETE) in a new Message.what back to
3632             // ClientModeImpl so that we can continue.
3633             // TODO(b/159060934): Need to ensure that CMD_PRE_DHCP_ACTION_COMPLETE is sent back to
3634             //  the ClientModeImpl instance that originally sent it. Right now it is sent back to
3635             //  all ClientModeImpl instances by WifiP2pConnection.
3636             mWifiP2pConnection.sendMessage(
3637                     WifiP2pServiceImpl.BLOCK_DISCOVERY,
3638                     WifiP2pServiceImpl.ENABLED,
3639                     CMD_PRE_DHCP_ACTION_COMPLETE);
3640         } else {
3641             // If the p2p service is not running, we can proceed directly.
3642             sendMessage(CMD_PRE_DHCP_ACTION_COMPLETE);
3643         }
3644     }
3645 
addLayer2PacketsToHlpReq(List<Layer2PacketParcelable> packets)3646     void addLayer2PacketsToHlpReq(List<Layer2PacketParcelable> packets) {
3647         List<Layer2PacketParcelable> mLayer2Packet = packets;
3648         if ((mLayer2Packet != null) && (mLayer2Packet.size() > 0)) {
3649             mWifiNative.flushAllHlp(mInterfaceName);
3650 
3651             for (int j = 0; j < mLayer2Packet.size(); j++) {
3652                 byte [] bytes = mLayer2Packet.get(j).payload;
3653                 byte [] payloadBytes = Arrays.copyOfRange(bytes, 12, bytes.length);
3654                 MacAddress dstAddress = mLayer2Packet.get(j).dstMacAddress;
3655 
3656                 mWifiNative.addHlpReq(mInterfaceName, dstAddress, payloadBytes);
3657             }
3658         }
3659     }
3660 
handlePostDhcpSetup()3661     void handlePostDhcpSetup() {
3662         /* Restore power save and suspend optimizations */
3663         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
3664         setPowerSave(POWER_SAVE_CLIENT_DHCP, true);
3665 
3666         if (mWifiP2pConnection.isConnected()) {
3667             mWifiP2pConnection.sendMessage(
3668                     WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
3669         }
3670 
3671         // Set the coexistence mode back to its default value
3672         mWifiNative.setBluetoothCoexistenceMode(
3673                 mInterfaceName, WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
3674     }
3675 
3676     /**
3677      * Set power save mode
3678      *
3679      * @param ps true to enable power save (default behavior)
3680      *           false to disable power save.
3681      * @return true for success, false for failure
3682      */
setPowerSave(@owerSaveClientType int client, boolean ps)3683     public boolean setPowerSave(@PowerSaveClientType int client, boolean ps) {
3684         if (mInterfaceName != null) {
3685             if (mVerboseLoggingEnabled) {
3686                 Log.d(getTag(), "Request to set power save for: " + mInterfaceName + " to: " + ps
3687                         + " requested by: " + client + ", mPowerSaveDisableRequests = "
3688                         + mPowerSaveDisableRequests);
3689             }
3690             if (ps) {
3691                 mPowerSaveDisableRequests &= ~client;
3692             } else {
3693                 mPowerSaveDisableRequests |= client;
3694             }
3695             boolean actualPs = mPowerSaveDisableRequests == 0;
3696             if (mVerboseLoggingEnabled) {
3697                 Log.d(getTag(), "Setting power save to: " + actualPs
3698                         + ", mPowerSaveDisableRequests = " + mPowerSaveDisableRequests);
3699             }
3700 
3701             mWifiNative.setPowerSave(mInterfaceName, actualPs);
3702         } else {
3703             Log.e(getTag(), "Failed to setPowerSave, interfaceName is null");
3704             return false;
3705         }
3706         return true;
3707     }
3708 
3709     /**
3710      * Enable power save.
3711      *
3712      * @return true for success, false for failure.
3713      */
enablePowerSave()3714     public boolean enablePowerSave() {
3715         return setPowerSave(~0, true);
3716     }
3717 
3718     /**
3719      * Set low latency mode
3720      *
3721      * @param enabled true to enable low latency
3722      *                false to disable low latency (default behavior).
3723      * @return true for success, false for failure
3724      */
setLowLatencyMode(boolean enabled)3725     public boolean setLowLatencyMode(boolean enabled) {
3726         if (mVerboseLoggingEnabled) {
3727             Log.d(getTag(), "Setting low latency mode to " + enabled);
3728         }
3729         if (!mWifiNative.setLowLatencyMode(enabled)) {
3730             Log.e(getTag(), "Failed to setLowLatencyMode");
3731             return false;
3732         }
3733         return true;
3734     }
3735 
getClientRoleForMetrics(WifiConfiguration config)3736     private int getClientRoleForMetrics(WifiConfiguration config) {
3737         ActiveModeManager.ClientRole clientRole = mClientModeManager.getRole();
3738         if (clientRole == ROLE_CLIENT_PRIMARY) {
3739             return config != null && config.fromWifiNetworkSpecifier
3740                     ? WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY
3741                     : WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY;
3742         } else if (clientRole == ROLE_CLIENT_LOCAL_ONLY) {
3743             return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY;
3744         } else if (clientRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3745             return mClientModeManager.isSecondaryInternet()
3746                     ? WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_SECONDARY_INTERNET
3747                     : WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_SECONDARY_LONG_LIVED;
3748         } else if (clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3749             return WifiStatsLog
3750                     .WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_SECONDARY_TRANSIENT;
3751         }
3752         return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_OTHERS;
3753     }
3754 
3755     /**
3756      * Inform other components that a new connection attempt is starting.
3757      */
reportConnectionAttemptStart( WifiConfiguration config, String targetBSSID, int roamType, int uid)3758     private void reportConnectionAttemptStart(
3759             WifiConfiguration config, String targetBSSID, int roamType, int uid) {
3760         boolean isOobPseudonymEnabled = false;
3761         if (config.enterpriseConfig != null && config.enterpriseConfig.isAuthenticationSimBased()
3762                 && mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(config.carrierId)) {
3763             isOobPseudonymEnabled = true;
3764         }
3765         int overlapWithLastConnectionMs =
3766                 mWifiMetrics.startConnectionEvent(
3767                         mInterfaceName, config, targetBSSID, roamType, isOobPseudonymEnabled,
3768                         getClientRoleForMetrics(config), uid);
3769         if (mDeviceConfigFacade.isOverlappingConnectionBugreportEnabled()
3770                 && overlapWithLastConnectionMs
3771                 > mDeviceConfigFacade.getOverlappingConnectionDurationThresholdMs()) {
3772             String bugTitle = "Wi-Fi BugReport: overlapping connection";
3773             String bugDetail = "Detect abnormal overlapping connection";
3774             mWifiDiagnostics.takeBugReport(bugTitle, bugDetail);
3775         }
3776         mWifiDiagnostics.reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_STARTED,
3777                 mClientModeManager);
3778         if (isPrimary()) {
3779             mWrongPasswordNotifier.onNewConnectionAttempt();
3780         }
3781     }
3782 
handleConnectionAttemptEndForDiagnostics(int level2FailureCode)3783     private void handleConnectionAttemptEndForDiagnostics(int level2FailureCode) {
3784         switch (level2FailureCode) {
3785             case WifiMetrics.ConnectionEvent.FAILURE_NONE:
3786                 break;
3787             case WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED:
3788                 // WifiDiagnostics doesn't care about pre-empted connections, or cases
3789                 // where we failed to initiate a connection attempt with supplicant.
3790                 break;
3791             case WifiMetrics.ConnectionEvent.FAILURE_NO_RESPONSE:
3792                 mWifiDiagnostics.reportConnectionEvent(
3793                         WifiDiagnostics.CONNECTION_EVENT_TIMEOUT, mClientModeManager);
3794                 break;
3795             default:
3796                 mWifiDiagnostics.reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_FAILED,
3797                         mClientModeManager);
3798         }
3799     }
3800 
3801     /**
3802      * Inform other components (WifiMetrics, WifiDiagnostics, WifiConnectivityManager, etc.) that
3803      * the current connection attempt has concluded.
3804      */
reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode, int level2FailureReason, int statusCode)3805     private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode,
3806             int level2FailureReason, int statusCode) {
3807         // if connected, this should be non-null.
3808         WifiConfiguration configuration = getConnectedWifiConfigurationInternal();
3809         if (configuration == null) {
3810             // If not connected, this should be non-null.
3811             configuration = getConnectingWifiConfigurationInternal();
3812         }
3813         if (configuration == null) {
3814             Log.e(TAG, "Unexpected null WifiConfiguration. Config may have been removed.");
3815             return;
3816         }
3817 
3818         String bssid = mLastBssid == null ? mTargetBssid : mLastBssid;
3819         String ssid = mWifiInfo.getSSID();
3820         if (WifiManager.UNKNOWN_SSID.equals(ssid)) {
3821             ssid = getConnectingSsidInternal();
3822         }
3823         if (level2FailureCode != WifiMetrics.ConnectionEvent.FAILURE_NONE) {
3824             int blocklistReason = convertToWifiBlocklistMonitorFailureReason(
3825                     level2FailureCode, level2FailureReason);
3826             if (blocklistReason != -1) {
3827                 mWifiScoreCard.noteConnectionFailure(mWifiInfo, mLastScanRssi, ssid,
3828                         blocklistReason);
3829                 checkAbnormalConnectionFailureAndTakeBugReport(ssid);
3830                 mWifiBlocklistMonitor.handleBssidConnectionFailure(bssid, configuration,
3831                         blocklistReason, mLastScanRssi);
3832                 WifiScoreCard.NetworkConnectionStats recentStats = mWifiScoreCard.lookupNetwork(
3833                         ssid).getRecentStats();
3834                 // Skip the secondary internet connection failure for association rejection
3835                 final boolean shouldSkip = isSecondaryInternet() &&
3836                         (level2FailureCode
3837                                 == WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT
3838                                 || level2FailureCode
3839                                 == WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION);
3840                 if (recentStats.getCount(WifiScoreCard.CNT_CONSECUTIVE_CONNECTION_FAILURE)
3841                         >= WifiBlocklistMonitor.NUM_CONSECUTIVE_FAILURES_PER_NETWORK_EXP_BACKOFF
3842                         && configuration.getNetworkSelectionStatus().isNetworkEnabled()
3843                         && !shouldSkip) {
3844                     mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
3845                             WifiConfiguration.NetworkSelectionStatus.DISABLED_CONSECUTIVE_FAILURES);
3846                 }
3847                 if (recentStats.getCount(WifiScoreCard.CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE)
3848                         >= THRESHOLD_TO_PERM_WRONG_PASSWORD) {
3849                     mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
3850                             WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
3851                 }
3852             }
3853         }
3854 
3855         if (configuration.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
3856             if (level2FailureCode == WifiMetrics.ConnectionEvent.FAILURE_NONE) {
3857                 mWifiMetrics.incrementNumOfCarrierWifiConnectionSuccess();
3858             } else if (level2FailureCode
3859                             == WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE
3860                     && level2FailureReason
3861                             != WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE) {
3862                 mWifiMetrics.incrementNumOfCarrierWifiConnectionAuthFailure();
3863             } else {
3864                 mWifiMetrics.incrementNumOfCarrierWifiConnectionNonAuthFailure();
3865             }
3866         }
3867 
3868         boolean isAssociationRejection = level2FailureCode
3869                 == WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION;
3870         boolean isAuthenticationFailure = level2FailureCode
3871                 == WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE
3872                 && level2FailureReason != WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD;
3873         if ((isAssociationRejection || isAuthenticationFailure)
3874                 && mWifiConfigManager.isInFlakyRandomizationSsidHotlist(mTargetNetworkId)
3875                 && isPrimary()) {
3876             mConnectionFailureNotifier
3877                     .showFailedToConnectDueToNoRandomizedMacSupportNotification(mTargetNetworkId);
3878         }
3879 
3880         ScanResult candidate = configuration.getNetworkSelectionStatus().getCandidate();
3881         int frequency = mWifiInfo.getFrequency();
3882         if (frequency == WifiInfo.UNKNOWN_FREQUENCY && candidate != null) {
3883             frequency = candidate.frequency;
3884         }
3885         mWifiMetrics.endConnectionEvent(mInterfaceName, level2FailureCode,
3886                 connectivityFailureCode, level2FailureReason, frequency, statusCode);
3887         mWifiConnectivityManager.handleConnectionAttemptEnded(
3888                 mClientModeManager, level2FailureCode, level2FailureReason, bssid,
3889                 configuration);
3890         mNetworkFactory.handleConnectionAttemptEnded(level2FailureCode, configuration, bssid,
3891                 level2FailureReason);
3892         mWifiNetworkSuggestionsManager.handleConnectionAttemptEnded(
3893                 level2FailureCode, configuration, getConnectedBssidInternal());
3894         if (candidate != null
3895                 && !TextUtils.equals(candidate.BSSID, getConnectedBssidInternal())) {
3896             mWifiMetrics.incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3897         }
3898         handleConnectionAttemptEndForDiagnostics(level2FailureCode);
3899     }
3900 
3901     /* If this connection attempt fails after 802.1x stage, clear intermediate cached data. */
clearNetworkCachedDataIfNeeded(WifiConfiguration config, int reason)3902     void clearNetworkCachedDataIfNeeded(WifiConfiguration config, int reason) {
3903         if (config == null) return;
3904 
3905         switch(reason) {
3906             case StaIfaceReasonCode.UNSPECIFIED:
3907             case StaIfaceReasonCode.DEAUTH_LEAVING:
3908                 logi("Keep PMK cache for network disconnection reason " + reason);
3909                 break;
3910             default:
3911                 mWifiNative.removeNetworkCachedData(config.networkId);
3912                 break;
3913         }
3914     }
3915 
3916     /**
3917      * Returns the sufficient RSSI for the frequency that this network is last seen on.
3918      */
getSufficientRssi(int networkId, String bssid)3919     private int getSufficientRssi(int networkId, String bssid) {
3920         ScanDetailCache scanDetailCache =
3921                 mWifiConfigManager.getScanDetailCacheForNetwork(networkId);
3922         if (scanDetailCache == null) {
3923             return WifiInfo.INVALID_RSSI;
3924         }
3925         ScanResult scanResult = scanDetailCache.getScanResult(bssid);
3926         if (scanResult == null) {
3927             return WifiInfo.INVALID_RSSI;
3928         }
3929         return mScoringParams.getSufficientRssi(scanResult.frequency);
3930     }
3931 
convertToWifiBlocklistMonitorFailureReason( int level2FailureCode, int failureReason)3932     private int convertToWifiBlocklistMonitorFailureReason(
3933             int level2FailureCode, int failureReason) {
3934         switch (level2FailureCode) {
3935             case WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT:
3936                 return WifiBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT;
3937             case WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION:
3938                 if (failureReason == WifiMetricsProto.ConnectionEvent
3939                         .ASSOCIATION_REJECTION_AP_UNABLE_TO_HANDLE_NEW_STA) {
3940                     return WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA;
3941                 }
3942                 return WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION;
3943             case WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE:
3944                 if (failureReason == WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD) {
3945                     return WifiBlocklistMonitor.REASON_WRONG_PASSWORD;
3946                 } else if (failureReason == WifiMetricsProto.ConnectionEvent
3947                         .AUTH_FAILURE_EAP_FAILURE) {
3948                     return WifiBlocklistMonitor.REASON_EAP_FAILURE;
3949                 }
3950                 return WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE;
3951             case WifiMetrics.ConnectionEvent.FAILURE_DHCP:
3952                 return WifiBlocklistMonitor.REASON_DHCP_FAILURE;
3953             case WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION:
3954                 if (failureReason == WifiMetricsProto.ConnectionEvent.DISCONNECTION_NON_LOCAL) {
3955                     return WifiBlocklistMonitor.REASON_NONLOCAL_DISCONNECT_CONNECTING;
3956                 }
3957                 return -1;
3958             case WifiMetrics.ConnectionEvent.FAILURE_NO_RESPONSE:
3959                 return WifiBlocklistMonitor.REASON_FAILURE_NO_RESPONSE;
3960             default:
3961                 return -1;
3962         }
3963     }
3964 
handleIPv4Success(DhcpResultsParcelable dhcpResults)3965     private void handleIPv4Success(DhcpResultsParcelable dhcpResults) {
3966         if (mVerboseLoggingEnabled) {
3967             logd("handleIPv4Success <" + dhcpResults.toString() + ">");
3968             logd("link address " + dhcpResults.baseConfiguration.getIpAddress());
3969         }
3970 
3971         Inet4Address addr;
3972         synchronized (mDhcpResultsParcelableLock) {
3973             mDhcpResultsParcelable = dhcpResults;
3974             addr = (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress();
3975         }
3976 
3977         if (mIsAutoRoaming) {
3978             int previousAddress = mWifiInfo.getIpAddress();
3979             int newAddress = Inet4AddressUtils.inet4AddressToIntHTL(addr);
3980             if (previousAddress != newAddress) {
3981                 logd("handleIPv4Success, roaming and address changed"
3982                         + mWifiInfo + " got: " + addr);
3983             }
3984         }
3985 
3986         mWifiInfo.setInetAddress(addr);
3987 
3988         final WifiConfiguration config = getConnectedWifiConfigurationInternal();
3989         if (config != null) {
3990             updateWifiInfoWhenConnected(config);
3991             mWifiConfigManager.updateRandomizedMacExpireTime(config, dhcpResults.leaseDuration);
3992             mWifiBlocklistMonitor.handleDhcpProvisioningSuccess(mLastBssid, mWifiInfo.getSSID());
3993         }
3994 
3995         // Set meteredHint if DHCP result says network is metered
3996         if (dhcpResults.vendorInfo != null && dhcpResults.vendorInfo.contains("ANDROID_METERED")) {
3997             mWifiInfo.setMeteredHint(true);
3998             mWifiMetrics.addMeteredStat(config, true);
3999         } else {
4000             mWifiMetrics.addMeteredStat(config, false);
4001         }
4002 
4003         updateCapabilities();
4004         updateCurrentConnectionInfo();
4005     }
4006 
handleSuccessfulIpConfiguration()4007     private void handleSuccessfulIpConfiguration() {
4008         mLastSignalLevel = -1; // Force update of signal strength
4009         WifiConfiguration c = getConnectedWifiConfigurationInternal();
4010         if (c != null) {
4011             // Reset IP failure tracking
4012             c.getNetworkSelectionStatus().clearDisableReasonCounter(
4013                     WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4014         }
4015     }
4016 
handleIPv4Failure()4017     private void handleIPv4Failure() {
4018         // TODO: Move this to provisioning failure, not DHCP failure.
4019         // DHCPv4 failure is expected on an IPv6-only network.
4020         mWifiDiagnostics.triggerBugReportDataCapture(WifiDiagnostics.REPORT_REASON_DHCP_FAILURE);
4021         if (mVerboseLoggingEnabled) {
4022             int count = -1;
4023             WifiConfiguration config = getConnectedWifiConfigurationInternal();
4024             if (config != null) {
4025                 count = config.getNetworkSelectionStatus().getDisableReasonCounter(
4026                         WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4027             }
4028             log("DHCP failure count=" + count);
4029         }
4030         synchronized (mDhcpResultsParcelableLock) {
4031             mDhcpResultsParcelable = new DhcpResultsParcelable();
4032         }
4033         if (mVerboseLoggingEnabled) {
4034             logd("handleIPv4Failure");
4035         }
4036     }
4037 
handleIpConfigurationLost()4038     private void handleIpConfigurationLost() {
4039         mWifiInfo.setInetAddress(null);
4040         mWifiInfo.setMeteredHint(false);
4041 
4042         mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
4043                 WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4044 
4045         /* DHCP times out after about 30 seconds, we do a
4046          * disconnect thru supplicant, we will let autojoin retry connecting to the network
4047          */
4048         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_IP_PROVISIONING_FAILURE;
4049         mWifiNative.disconnect(mInterfaceName);
4050         updateCurrentConnectionInfo();
4051     }
4052 
handleIpReachabilityLost(int lossReason)4053     private void handleIpReachabilityLost(int lossReason) {
4054         mWifiBlocklistMonitor.handleBssidConnectionFailure(mWifiInfo.getBSSID(),
4055                 getConnectedWifiConfiguration(),
4056                 WifiBlocklistMonitor.REASON_ABNORMAL_DISCONNECT, mWifiInfo.getRssi());
4057         mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
4058         mWifiInfo.setInetAddress(null);
4059         mWifiInfo.setMeteredHint(false);
4060 
4061         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NUD_FAILURE_GENERIC;
4062         if (lossReason == ReachabilityLossReason.ROAM) {
4063             mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NUD_FAILURE_ROAM;
4064         } else if (lossReason == ReachabilityLossReason.CONFIRM) {
4065             mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NUD_FAILURE_CONFIRM;
4066         } else if (lossReason == ReachabilityLossReason.ORGANIC) {
4067             mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NUD_FAILURE_ORGANIC;
4068         }
4069         // Disconnect via supplicant, and let autojoin retry connecting to the network.
4070         mWifiNative.disconnect(mInterfaceName);
4071         updateCurrentConnectionInfo();
4072     }
4073 
4074     /**
4075      * Process IP Reachability failures by recreating a new IpClient instance to refresh L3
4076      * provisioning while keeping L2 still connected.
4077      *
4078      * This method is invoked only upon receiving reachability failure post roaming or triggered
4079      * from Wi-Fi RSSI polling or organic kernel probe.
4080      */
processIpReachabilityFailure(int lossReason)4081     private void processIpReachabilityFailure(int lossReason) {
4082         WifiConfiguration config = getConnectedWifiConfigurationInternal();
4083         if (config == null) {
4084             // special case for IP reachability lost which happens right after linked network
4085             // roaming. The linked network roaming reset the mLastNetworkId which results in
4086             // the connected configuration to be null.
4087             config = getConnectingWifiConfigurationInternal();
4088             if (config == null) {
4089                 // config could be null if it had been removed from WifiConfigManager. In this case
4090                 // we should simply disconnect.
4091                 handleIpReachabilityLost(lossReason);
4092                 return;
4093             }
4094         }
4095         final long curTime = mClock.getElapsedSinceBootMillis();
4096         if (curTime - mNudFailureCounter.first <= mWifiGlobals.getRepeatedNudFailuresWindowMs()) {
4097             mNudFailureCounter = new Pair<>(curTime, mNudFailureCounter.second + 1);
4098         } else {
4099             mNudFailureCounter = new Pair<>(curTime, 1);
4100         }
4101         if (mNudFailureCounter.second >= mWifiGlobals.getRepeatedNudFailuresThreshold()) {
4102             // Disable and disconnect due to repeated NUD failures within limited time window.
4103             mWifiConfigManager.updateNetworkSelectionStatus(config.networkId,
4104                     WifiConfiguration.NetworkSelectionStatus.DISABLED_REPEATED_NUD_FAILURES);
4105             handleIpReachabilityLost(lossReason);
4106             mNudFailureCounter = new Pair<>(0L, 0);
4107             return;
4108         }
4109 
4110         final NetworkAgentConfig naConfig = getNetworkAgentConfigInternal(config);
4111         final NetworkCapabilities nc = getCapabilities(
4112                 getConnectedWifiConfigurationInternal(), getConnectedBssidInternal());
4113 
4114         mWifiInfo.setInetAddress(null);
4115         if (mNetworkAgent != null) {
4116             if (SdkLevel.isAtLeastT()) {
4117                 mNetworkAgent.unregisterAfterReplacement(NETWORK_AGENT_TEARDOWN_DELAY_MS);
4118             } else {
4119                 mNetworkAgent.unregister();
4120             }
4121         }
4122         mNetworkAgent = mWifiInjector.makeWifiNetworkAgent(nc, mLinkProperties, naConfig,
4123                 mNetworkFactory.getProvider(), new WifiNetworkAgentCallback());
4124         mWifiScoreReport.setNetworkAgent(mNetworkAgent);
4125         if (SdkLevel.isAtLeastT()) {
4126             mQosPolicyRequestHandler.setNetworkAgent(mNetworkAgent);
4127         }
4128 
4129         // Shutdown IpClient and cleanup IpClientCallbacks instance before transition to
4130         // WaitBeforeL3ProvisioningState, in order to prevent WiFi state machine from
4131         // processing the posted message sent from the legacy IpClientCallbacks instance,
4132         // see b/286338765.
4133         maybeShutdownIpclient();
4134         transitionTo(mWaitBeforeL3ProvisioningState);
4135 
4136         updateCurrentConnectionInfo();
4137     }
4138 
processLegacyIpReachabilityLost(int lossReason)4139     private void processLegacyIpReachabilityLost(int lossReason) {
4140         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_IP_REACHABILITY_LOST);
4141         mWifiMetrics.logWifiIsUnusableEvent(mInterfaceName,
4142                 WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST);
4143         mWifiMetrics.addToWifiUsabilityStatsList(mInterfaceName,
4144                 WifiUsabilityStats.LABEL_BAD,
4145                 WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST, -1);
4146         if (mWifiGlobals.getIpReachabilityDisconnectEnabled()) {
4147             handleIpReachabilityLost(lossReason);
4148         } else {
4149             logd("CMD_IP_REACHABILITY_LOST but disconnect disabled -- ignore");
4150         }
4151     }
4152 
shouldIgnoreNudDisconnectForWapiInCn()4153     private boolean shouldIgnoreNudDisconnectForWapiInCn() {
4154         // temporary work-around for <=U devices
4155         if (SdkLevel.isAtLeastV()) return false;
4156 
4157         if (!mWifiGlobals.disableNudDisconnectsForWapiInSpecificCc() || !"CN".equalsIgnoreCase(
4158                 mWifiInjector.getWifiCountryCode().getCountryCode())) {
4159             return false;
4160         }
4161         WifiConfiguration config = getConnectedWifiConfigurationInternal();
4162         return config != null && (config.allowedProtocols.get(WifiConfiguration.Protocol.WAPI)
4163                 || config.getAuthType() == WifiConfiguration.KeyMgmt.NONE);
4164     }
4165 
handleIpReachabilityFailure(@onNull ReachabilityLossInfoParcelable lossInfo)4166     private void handleIpReachabilityFailure(@NonNull ReachabilityLossInfoParcelable lossInfo) {
4167         if (lossInfo == null) {
4168             Log.e(getTag(), "lossInfo should never be null");
4169             processLegacyIpReachabilityLost(-1);
4170             return;
4171         }
4172 
4173         switch (lossInfo.reason) {
4174             case ReachabilityLossReason.ROAM:
4175                 processIpReachabilityFailure(lossInfo.reason);
4176                 break;
4177             case ReachabilityLossReason.CONFIRM:
4178             case ReachabilityLossReason.ORGANIC: {
4179                 if (shouldIgnoreNudDisconnectForWapiInCn()) {
4180                     logd("CMD_IP_REACHABILITY_FAILURE but disconnect disabled for WAPI -- ignore");
4181                     return;
4182                 }
4183 
4184                 if (mDeviceConfigFacade.isHandleRssiOrganicKernelFailuresEnabled()) {
4185                     processIpReachabilityFailure(lossInfo.reason);
4186                 } else {
4187                     processLegacyIpReachabilityLost(lossInfo.reason);
4188                 }
4189                 break;
4190             }
4191             default:
4192                 logd("Invalid failure reason " + lossInfo.reason + "from onIpReachabilityFailure");
4193         }
4194     }
4195 
getNetworkAgentConfigInternal(WifiConfiguration config)4196     private NetworkAgentConfig getNetworkAgentConfigInternal(WifiConfiguration config) {
4197         boolean explicitlySelected = false;
4198         // Non primary CMMs is never user selected. This prevents triggering the No Internet
4199         // dialog for those networks, which is difficult to handle.
4200         if (isPrimary() && isRecentlySelectedByTheUser(config)) {
4201             // If explicitlySelected is true, the network was selected by the user via Settings
4202             // or QuickSettings. If this network has Internet access, switch to it. Otherwise,
4203             // switch to it only if the user confirms that they really want to switch, or has
4204             // already confirmed and selected "Don't ask again".
4205             explicitlySelected =
4206                     mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid);
4207             if (mVerboseLoggingEnabled) {
4208                 log("Network selected by UID " + config.lastConnectUid
4209                         + " explicitlySelected=" + explicitlySelected);
4210             }
4211         }
4212         NetworkAgentConfig.Builder naConfigBuilder = new NetworkAgentConfig.Builder()
4213                 .setLegacyType(ConnectivityManager.TYPE_WIFI)
4214                 .setLegacyTypeName(NETWORKTYPE)
4215                 .setExplicitlySelected(explicitlySelected)
4216                 .setUnvalidatedConnectivityAcceptable(
4217                         explicitlySelected && config.noInternetAccessExpected)
4218                 .setPartialConnectivityAcceptable(config.noInternetAccessExpected);
4219         if (config.carrierMerged) {
4220             String subscriberId = null;
4221             TelephonyManager subMgr = mTelephonyManager.createForSubscriptionId(
4222                     config.subscriptionId);
4223             if (subMgr != null) {
4224                 subscriberId = subMgr.getSubscriberId();
4225             }
4226             if (subscriberId != null) {
4227                 naConfigBuilder.setSubscriberId(subscriberId);
4228             }
4229         }
4230         if (mVcnManager == null && SdkLevel.isAtLeastS()) {
4231             mVcnManager = mContext.getSystemService(VcnManager.class);
4232         }
4233         if (mVcnManager != null && mVcnPolicyChangeListener == null && SdkLevel.isAtLeastS()) {
4234             mVcnPolicyChangeListener = new WifiVcnNetworkPolicyChangeListener();
4235             mVcnManager.addVcnNetworkPolicyChangeListener(new HandlerExecutor(getHandler()),
4236                     mVcnPolicyChangeListener);
4237         }
4238         return naConfigBuilder.build();
4239     }
4240 
4241     /*
4242      * Read a MAC address in /proc/net/arp, used by ClientModeImpl
4243      * so as to record MAC address of default gateway.
4244      **/
macAddressFromRoute(String ipAddress)4245     private String macAddressFromRoute(String ipAddress) {
4246         String macAddress = null;
4247         BufferedReader reader = null;
4248         try {
4249             reader = mWifiInjector.createBufferedReader(ARP_TABLE_PATH);
4250 
4251             // Skip over the line bearing column titles
4252             String line = reader.readLine();
4253 
4254             while ((line = reader.readLine()) != null) {
4255                 String[] tokens = line.split("[ ]+");
4256                 if (tokens.length < 6) {
4257                     continue;
4258                 }
4259 
4260                 // ARP column format is
4261                 // IPAddress HWType Flags HWAddress Mask Device
4262                 String ip = tokens[0];
4263                 String mac = tokens[3];
4264 
4265                 if (TextUtils.equals(ipAddress, ip)) {
4266                     macAddress = mac;
4267                     break;
4268                 }
4269             }
4270 
4271             if (macAddress == null) {
4272                 loge("Did not find remoteAddress {" + ipAddress + "} in /proc/net/arp");
4273             }
4274 
4275         } catch (FileNotFoundException e) {
4276             loge("Could not open /proc/net/arp to lookup mac address");
4277         } catch (IOException e) {
4278             loge("Could not read /proc/net/arp to lookup mac address");
4279         } finally {
4280             try {
4281                 if (reader != null) {
4282                     reader.close();
4283                 }
4284             } catch (IOException e) {
4285                 // Do nothing
4286             }
4287         }
4288         return macAddress;
4289 
4290     }
4291 
4292     /**
4293      * Determine if the specified auth failure is considered to be a permanent wrong password
4294      * failure. The criteria for such failure is when wrong password error is detected
4295      * and the network had never been connected before.
4296      *
4297      * For networks that have previously connected successfully, we consider wrong password
4298      * failures to be temporary, to be on the conservative side.  Since this might be the
4299      * case where we are trying to connect to a wrong network (e.g. A network with same SSID
4300      * but different password).
4301      */
isPermanentWrongPasswordFailure(int networkId, int reasonCode)4302     private boolean isPermanentWrongPasswordFailure(int networkId, int reasonCode) {
4303         if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD) {
4304             return false;
4305         }
4306         WifiConfiguration network = mWifiConfigManager.getConfiguredNetwork(networkId);
4307         if (network != null && network.getNetworkSelectionStatus().hasEverConnected()) {
4308             return false;
4309         }
4310         return true;
4311     }
4312 
4313      /**
4314      * Dynamically change the MAC address to use the locally randomized
4315      * MAC address generated for each network.
4316      * @param config WifiConfiguration with mRandomizedMacAddress to change into. If the address
4317      * is masked out or not set, it will generate a new random MAC address.
4318      */
configureRandomizedMacAddress(WifiConfiguration config)4319     private void configureRandomizedMacAddress(WifiConfiguration config) {
4320         if (config == null) {
4321             Log.e(getTag(), "No config to change MAC address to");
4322             return;
4323         }
4324         String currentMacString = mWifiNative.getMacAddress(mInterfaceName);
4325         MacAddress currentMac = NativeUtil.getMacAddressOrNull(currentMacString);
4326         MacAddress newMac = mWifiConfigManager.getRandomizedMacAndUpdateIfNeeded(config,
4327                 isSecondaryInternet() && mClientModeManager.isSecondaryInternetDbsAp());
4328         if (!WifiConfiguration.isValidMacAddressForRandomization(newMac)) {
4329             Log.wtf(getTag(), "Config generated an invalid MAC address");
4330         } else if (Objects.equals(newMac, currentMac)) {
4331             Log.d(getTag(), "No changes in MAC address");
4332         } else {
4333             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_MAC_CHANGE, config);
4334             boolean setMacSuccess =
4335                     mWifiNative.setStaMacAddress(mInterfaceName, newMac);
4336             if (setMacSuccess) {
4337                 mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, newMac);
4338             }
4339             if (mVerboseLoggingEnabled) {
4340                 Log.d(getTag(), "ConnectedMacRandomization SSID(" + config.getPrintableSsid()
4341                         + "). setMacAddress(" + newMac.toString() + ") from "
4342                         + currentMacString + " = " + setMacSuccess);
4343             }
4344         }
4345     }
4346 
4347     /**
4348      * Sets the current MAC to the factory MAC address.
4349      */
setCurrentMacToFactoryMac(WifiConfiguration config)4350     private void setCurrentMacToFactoryMac(WifiConfiguration config) {
4351         MacAddress factoryMac = retrieveFactoryMacAddressAndStoreIfNecessary();
4352         if (factoryMac == null) {
4353             Log.e(getTag(), "Fail to set factory MAC address. Factory MAC is null.");
4354             return;
4355         }
4356         String currentMacStr = mWifiNative.getMacAddress(mInterfaceName);
4357         if (!TextUtils.equals(currentMacStr, factoryMac.toString())) {
4358             if (mWifiNative.setStaMacAddress(mInterfaceName, factoryMac)) {
4359                 mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, factoryMac);
4360                 mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_MAC_CHANGE, config);
4361             } else {
4362                 Log.e(getTag(), "Failed to set MAC address to " + "'"
4363                         + factoryMac.toString() + "'");
4364             }
4365         }
4366     }
4367 
4368     /**
4369      * Helper method to start other services and get state ready for client mode
4370      */
setupClientMode()4371     private void setupClientMode() {
4372         Log.d(getTag(), "setupClientMode() ifacename = " + mInterfaceName);
4373 
4374         setMulticastFilter(true);
4375         registerForWifiMonitorEvents();
4376         if (isPrimary()) {
4377             mWifiLastResortWatchdog.clearAllFailureCounts();
4378         }
4379         mWifiNative.setSupplicantLogLevel(mVerboseLoggingEnabled);
4380 
4381         // Initialize data structures
4382         mTargetBssid = SUPPLICANT_BSSID_ANY;
4383         mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4384         mLastBssid = null;
4385         mIpProvisioningTimedOut = false;
4386         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4387         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
4388         mLastSimBasedConnectionCarrierName = null;
4389         mLastSignalLevel = -1;
4390         mEnabledTdlsPeers.clear();
4391         // TODO: b/79504296 This broadcast has been deprecated and should be removed
4392         sendSupplicantConnectionChangedBroadcast(true);
4393 
4394         mWifiNative.setExternalSim(mInterfaceName, true);
4395 
4396         mWifiDiagnostics.startPktFateMonitoring(mInterfaceName);
4397         mWifiDiagnostics.startLogging(mInterfaceName);
4398 
4399         mMboOceController.enable();
4400 
4401         // Enable bluetooth coexistence scan mode when bluetooth connection is active.
4402         // When this mode is on, some of the low-level scan parameters used by the
4403         // driver are changed to reduce interference with bluetooth
4404         mWifiNative.setBluetoothCoexistenceScanMode(
4405                 mInterfaceName, mWifiGlobals.isBluetoothConnected());
4406         sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
4407 
4408         // Disable legacy multicast filtering, which on some chipsets defaults to enabled.
4409         // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
4410         // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
4411         // IpClient.Callback.setFallbackMulticastFilter()
4412         mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName);
4413         mWifiNative.stopFilteringMulticastV6Packets(mInterfaceName);
4414 
4415         // Set the right suspend mode settings
4416         mWifiNative.setSuspendOptimizations(mInterfaceName, mSuspendOptNeedsDisabled == 0
4417                 && mContext.getResources().getBoolean(
4418                         R.bool.config_wifiSuspendOptimizationsEnabled));
4419 
4420         enablePowerSave();
4421 
4422         // Disable wpa_supplicant from auto reconnecting.
4423         mWifiNative.enableStaAutoReconnect(mInterfaceName, false);
4424         // STA has higher priority over P2P
4425         mWifiNative.setConcurrencyPriority(true);
4426         if (mClientModeManager.getRole() == ROLE_CLIENT_PRIMARY) {
4427             // Loads the firmware roaming info which gets used in WifiBlocklistMonitor
4428             mWifiConnectivityHelper.getFirmwareRoamingInfo();
4429         }
4430 
4431         // Retrieve and store the factory MAC address (on first bootup).
4432         retrieveFactoryMacAddressAndStoreIfNecessary();
4433         updateCurrentConnectionInfo();
4434     }
4435 
4436     /**
4437      * Helper method to stop external services and clean up state from client mode.
4438      */
stopClientMode()4439     private void stopClientMode() {
4440         handleNetworkDisconnect(false,
4441                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__WIFI_DISABLED);
4442         // exiting supplicant started state is now only applicable to client mode
4443         mWifiDiagnostics.stopLogging(mInterfaceName);
4444 
4445         mMboOceController.disable();
4446         maybeShutdownIpclient();
4447         deregisterForWifiMonitorEvents(); // uses mInterfaceName, must call before nulling out
4448         // TODO: b/79504296 This broadcast has been deprecated and should be removed
4449         sendSupplicantConnectionChangedBroadcast(false);
4450     }
4451 
4452     /**
4453      * Helper method called when a L3 connection is successfully established to a network.
4454      */
registerConnected()4455     void registerConnected() {
4456         if (isPrimary()) {
4457             mWifiInjector.getActiveModeWarden().setCurrentNetwork(getCurrentNetwork());
4458         }
4459         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4460             WifiConfiguration config = getConnectedWifiConfigurationInternal();
4461             boolean shouldSetUserConnectChoice = config != null
4462                     && mIsUserSelected
4463                     && isRecentlySelectedByTheUser(config)
4464                     && (config.getNetworkSelectionStatus().hasEverConnected()
4465                     || config.isEphemeral());
4466             mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId,
4467                     mIsUserSelected, shouldSetUserConnectChoice, mWifiInfo.getRssi());
4468             // Notify PasspointManager of Passpoint network connected event.
4469             WifiConfiguration currentNetwork = getConnectedWifiConfigurationInternal();
4470             if (currentNetwork != null && currentNetwork.isPasspoint()) {
4471                 mPasspointManager.onPasspointNetworkConnected(
4472                         currentNetwork.getProfileKey(), currentNetwork.SSID);
4473             }
4474         }
4475     }
4476 
registerDisconnected()4477     void registerDisconnected() {
4478         // The role of the ClientModeManager may have been changed to scan only before handling
4479         // the network disconnect.
4480         if (isPrimary() || mClientModeManager.getRole() == ROLE_CLIENT_SCAN_ONLY) {
4481             mWifiInjector.getActiveModeWarden().setCurrentNetwork(getCurrentNetwork());
4482         }
4483         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4484             mWifiConfigManager.updateNetworkAfterDisconnect(mLastNetworkId);
4485         }
4486     }
4487 
4488     /**
4489      * Returns WifiConfiguration object corresponding to the currently connected network, null if
4490      * not connected.
4491      */
getConnectedWifiConfigurationInternal()4492     @Nullable private WifiConfiguration getConnectedWifiConfigurationInternal() {
4493         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
4494             return null;
4495         }
4496         return mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
4497     }
4498 
4499     /**
4500      * Returns WifiConfiguration object corresponding to the currently connecting network, null if
4501      * not connecting.
4502      */
getConnectingWifiConfigurationInternal()4503     @Nullable private WifiConfiguration getConnectingWifiConfigurationInternal() {
4504         if (mTargetNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
4505             return null;
4506         }
4507         return mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
4508     }
4509 
getConnectedBssidInternal()4510     @Nullable private String getConnectedBssidInternal() {
4511         return mLastBssid;
4512     }
4513 
getConnectingBssidInternal()4514     @Nullable private String getConnectingBssidInternal() {
4515         return mTargetBssid;
4516     }
4517 
4518     /**
4519      * Returns WifiConfiguration object corresponding to the currently connected network, null if
4520      * not connected.
4521      */
4522     @Override
getConnectedWifiConfiguration()4523     @Nullable public WifiConfiguration getConnectedWifiConfiguration() {
4524         if (!isConnected()) return null;
4525         return getConnectedWifiConfigurationInternal();
4526     }
4527 
4528     /**
4529      * Returns WifiConfiguration object corresponding to the currently connecting network, null if
4530      * not connecting.
4531      */
4532     @Override
getConnectingWifiConfiguration()4533     @Nullable public WifiConfiguration getConnectingWifiConfiguration() {
4534         if (!isConnecting() && !isRoaming()) return null;
4535         return getConnectingWifiConfigurationInternal();
4536     }
4537 
4538     @Override
getConnectedBssid()4539     @Nullable public String getConnectedBssid() {
4540         if (!isConnected()) return null;
4541         return getConnectedBssidInternal();
4542     }
4543 
4544     @Override
getConnectingBssid()4545     @Nullable public String getConnectingBssid() {
4546         if (!isConnecting() && !isRoaming()) return null;
4547         return getConnectingBssidInternal();
4548     }
4549 
getCurrentScanResult()4550     ScanResult getCurrentScanResult() {
4551         WifiConfiguration config = getConnectedWifiConfigurationInternal();
4552         if (config == null) {
4553             return null;
4554         }
4555         String bssid = mWifiInfo.getBSSID();
4556         if (bssid == null) {
4557             bssid = mTargetBssid;
4558         }
4559         ScanDetailCache scanDetailCache =
4560                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
4561 
4562         if (scanDetailCache == null) {
4563             return null;
4564         }
4565 
4566         return scanDetailCache.getScanResult(bssid);
4567     }
4568 
getCurrentBssidInternalMacAddress()4569     private MacAddress getCurrentBssidInternalMacAddress() {
4570         return NativeUtil.getMacAddressOrNull(mLastBssid);
4571     }
4572 
connectToNetwork(WifiConfiguration config)4573     private void connectToNetwork(WifiConfiguration config) {
4574         if ((config != null) && mWifiNative.connectToNetwork(mInterfaceName, config)) {
4575             // Update the internal config once the connection request is accepted.
4576             mWifiConfigManager.setNetworkLastUsedSecurityParams(config.networkId,
4577                     config.getNetworkSelectionStatus().getCandidateSecurityParams());
4578             mWifiLastResortWatchdog.noteStartConnectTime(config.networkId);
4579             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_START_CONNECT, config);
4580             mIsAutoRoaming = false;
4581             transitionTo(mL2ConnectingState);
4582         } else {
4583             loge("CMD_START_CONNECT Failed to start connection to network " + config);
4584             mTargetWifiConfiguration = null;
4585             stopIpClient();
4586             reportConnectionAttemptEnd(
4587                     WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
4588                     WifiMetricsProto.ConnectionEvent.HLF_NONE,
4589                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
4590         }
4591     }
4592 
makeIpClient()4593     private void makeIpClient() {
4594         mIpClientCallbacks = new IpClientCallbacksImpl();
4595         mFacade.makeIpClient(mContext, mInterfaceName, mIpClientCallbacks);
4596         mIpClientCallbacks.awaitCreation();
4597     }
4598 
maybeShutdownIpclient()4599     private void maybeShutdownIpclient() {
4600         if (mIpClient == null) return;
4601         if (!mIpClient.shutdown()) {
4602             logd("Fail to shut down IpClient");
4603             return;
4604         }
4605 
4606         // Block to make sure IpClient has really shut down, lest cleanup
4607         // race with, say, bringup code over in tethering.
4608         mIpClientCallbacks.awaitShutdown();
4609         mIpClientCallbacks = null;
4610         mIpClient = null;
4611     }
4612 
4613     // Always use "arg1" to take the current IpClient callbacks index to check if the callbacks
4614     // come from the current mIpClientCallbacks instance.
isFromCurrentIpClientCallbacks(Message msg)4615     private boolean isFromCurrentIpClientCallbacks(Message msg) {
4616         if (mIpClientCallbacks == null || msg == null) return false;
4617         return mIpClientCallbacks.getCallbackIndex() == msg.arg1;
4618     }
4619 
4620     /********************************************************
4621      * HSM states
4622      *******************************************************/
4623 
4624     class ConnectableState extends RunnerState {
4625         private boolean mIsScreenStateChangeReceiverRegistered = false;
4626         WifiDeviceStateChangeManager.StateChangeCallback mScreenStateChangeReceiver =
4627                 new WifiDeviceStateChangeManager.StateChangeCallback() {
4628                     @Override
4629                     public void onScreenStateChanged(boolean screenOn) {
4630                         if (screenOn) {
4631                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
4632                         } else {
4633                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
4634                         }
4635                     }
4636                 };
4637 
ConnectableState(int threshold)4638         ConnectableState(int threshold) {
4639             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
4640         }
4641 
4642         @Override
enterImpl()4643         public void enterImpl() {
4644             Log.d(getTag(), "entering ConnectableState: ifaceName = " + mInterfaceName);
4645             setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
4646             if (mWifiGlobals.isConnectedMacRandomizationEnabled()) {
4647                 mFailedToResetMacAddress = !mWifiNative.setStaMacAddress(
4648                         mInterfaceName, MacAddressUtils.createRandomUnicastAddress());
4649                 if (mFailedToResetMacAddress) {
4650                     Log.e(getTag(), "Failed to set random MAC address on ClientMode creation");
4651                 }
4652             }
4653             mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
4654             updateCurrentConnectionInfo();
4655             mWifiStateTracker.updateState(mInterfaceName, WifiStateTracker.INVALID);
4656             makeIpClient();
4657         }
4658 
continueEnterSetup(IpClientManager ipClientManager)4659         private void continueEnterSetup(IpClientManager ipClientManager) {
4660             mIpClient = ipClientManager;
4661             setupClientMode();
4662 
4663             if (!mIsScreenStateChangeReceiverRegistered) {
4664                 mWifiDeviceStateChangeManager.registerStateChangeCallback(
4665                         mScreenStateChangeReceiver);
4666                 mIsScreenStateChangeReceiverRegistered = true;
4667             }
4668             // Learn the initial state of whether the screen is on.
4669             // We update this field when we receive broadcasts from the system.
4670             handleScreenStateChanged(mContext.getSystemService(PowerManager.class).isInteractive());
4671 
4672             if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
4673                 loge("Failed to remove networks on entering connect mode");
4674             }
4675             mWifiInfo.reset();
4676             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
4677 
4678             sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
4679 
4680             // Inform metrics that Wifi is Enabled (but not yet connected)
4681             mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
4682             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_WIFI_ENABLED);
4683             mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
4684             updateCurrentConnectionInfo();
4685         }
4686 
4687         @Override
exitImpl()4688         public void exitImpl() {
4689             // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
4690             mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_DISABLED);
4691             mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_WIFI_DISABLED);
4692 
4693             if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
4694                 loge("Failed to remove networks on exiting connect mode");
4695             }
4696             if (mIsScreenStateChangeReceiverRegistered) {
4697                 mWifiDeviceStateChangeManager.unregisterStateChangeCallback(
4698                         mScreenStateChangeReceiver);
4699                 mIsScreenStateChangeReceiverRegistered = false;
4700             }
4701 
4702             stopClientMode();
4703             mWifiScoreCard.doWrites();
4704         }
4705 
4706         @Override
getMessageLogRec(int what)4707         public String getMessageLogRec(int what) {
4708             return ClientModeImpl.class.getSimpleName() + "."
4709                     + ConnectableState.class.getSimpleName() + "." + getWhatToString(what);
4710         }
4711 
4712         @Override
processMessageImpl(Message message)4713         public boolean processMessageImpl(Message message) {
4714             switch (message.what) {
4715                 case CMD_IPCLIENT_CREATED:
4716                     if (!isFromCurrentIpClientCallbacks(message)) break;
4717                     if (mIpClient != null) {
4718                         loge("Setup connectable state again when IpClient is ready?");
4719                     } else {
4720                         IpClientManager ipClientManager = (IpClientManager) message.obj;
4721                         continueEnterSetup(ipClientManager);
4722                     }
4723                     break;
4724                 case CMD_ENABLE_RSSI_POLL: {
4725                     mEnableRssiPolling = (message.arg1 == 1);
4726                     break;
4727                 }
4728                 case CMD_SCREEN_STATE_CHANGED: {
4729                     handleScreenStateChanged(message.arg1 != 0);
4730                     break;
4731                 }
4732                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: {
4733                     if (mIpClient == null) {
4734                         logd("IpClient is not ready, "
4735                                 + "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST dropped");
4736                         break;
4737                     }
4738                     if (mWifiP2pConnection.shouldTemporarilyDisconnectWifi()) {
4739                         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
4740                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
4741                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_P2P_REQUESTED_DISCONNECT;
4742                         mWifiNative.disconnect(mInterfaceName);
4743                     } else {
4744                         mWifiNative.reconnect(mInterfaceName);
4745                     }
4746                     break;
4747                 }
4748                 case CMD_RECONNECT: {
4749                     WorkSource workSource = (WorkSource) message.obj;
4750                     mWifiConnectivityManager.forceConnectivityScan(workSource);
4751                     break;
4752                 }
4753                 case CMD_REASSOCIATE: {
4754                     if (mIpClient != null) {
4755                         logd("IpClient is not ready, REASSOCIATE dropped");
4756 
4757                         mWifiNative.reassociate(mInterfaceName);
4758                     }
4759                     break;
4760                 }
4761                 case CMD_START_CONNECT: {
4762                     if (mIpClient == null) {
4763                         logd("IpClient is not ready, START_CONNECT dropped");
4764 
4765                         break;
4766                     }
4767                     /* connect command coming from auto-join */
4768                     int netId = message.arg1;
4769                     int uid = message.arg2;
4770                     String bssid = (String) message.obj;
4771                     mSentHLPs = false;
4772                     // Stop lingering (if it was lingering before) if we start a new connection.
4773                     // This means that the ClientModeManager was reused for another purpose, so it
4774                     // should no longer be in lingering mode.
4775                     mClientModeManager.setShouldReduceNetworkScore(false);
4776 
4777                     if (!hasConnectionRequests()) {
4778                         if (mNetworkAgent == null) {
4779                             loge("CMD_START_CONNECT but no requests and not connected,"
4780                                     + " bailing");
4781                             break;
4782                         } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4783                             loge("CMD_START_CONNECT but no requests and connected, but app "
4784                                     + "does not have sufficient permissions, bailing");
4785                             break;
4786                         }
4787                     }
4788                     WifiConfiguration config =
4789                             mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
4790                     logd("CMD_START_CONNECT "
4791                             + " my state " + getCurrentState().getName()
4792                             + " nid=" + netId
4793                             + " roam=" + mIsAutoRoaming);
4794                     if (config == null) {
4795                         loge("CMD_START_CONNECT and no config, bail out...");
4796                         break;
4797                     }
4798                     mCurrentConnectionDetectedCaptivePortal = false;
4799                     mCurrentConnectionReportedCertificateExpired = false;
4800                     mTargetNetworkId = netId;
4801                     // Update scorecard while there is still state from existing connection
4802                     mLastScanRssi = mWifiConfigManager.findScanRssi(netId,
4803                             mWifiHealthMonitor.getScanRssiValidTimeMs());
4804                     mWifiScoreCard.noteConnectionAttempt(mWifiInfo, mLastScanRssi, config.SSID);
4805                     if (isPrimary()) {
4806                         mWifiBlocklistMonitor.setAllowlistSsids(config.SSID,
4807                                 Collections.emptyList());
4808                         mWifiBlocklistMonitor.updateFirmwareRoamingConfiguration(
4809                                 Set.of(config.SSID));
4810                     }
4811 
4812                     updateWifiConfigOnStartConnection(config, bssid);
4813                     reportConnectionAttemptStart(config, mTargetBssid,
4814                             WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED, uid);
4815 
4816                     String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);
4817                     mWifiInfo.setMacAddress(currentMacAddress);
4818                     updateCurrentConnectionInfo();
4819                     if (mVerboseLoggingEnabled) {
4820                         Log.i(getTag(), "Connecting with " + currentMacAddress
4821                                 + " as the mac address");
4822                     }
4823                     mWifiPseudonymManager.enableStrictConservativePeerModeIfSupported(config);
4824                     mTargetWifiConfiguration = config;
4825                     mNetworkNotFoundEventCount = 0;
4826                     /* Check for FILS configuration again after updating the config */
4827                     if (config.isFilsSha256Enabled() || config.isFilsSha384Enabled()) {
4828                         boolean isIpClientStarted = startIpClient(config, true);
4829                         if (isIpClientStarted) {
4830                             mIpClientWithPreConnection = true;
4831                             transitionTo(mL2ConnectingState);
4832                             break;
4833                         }
4834                     }
4835                     setSelectedRcoiForPasspoint(config);
4836 
4837                     // TOFU flow for devices that do not support this feature
4838                     mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration);
4839                     mLeafCertSent = false;
4840                     if (!isTrustOnFirstUseSupported()) {
4841                         mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected);
4842                     }
4843                     connectToNetwork(config);
4844                     break;
4845                 }
4846                 case CMD_START_FILS_CONNECTION: {
4847                     if (!isFromCurrentIpClientCallbacks(message)) break;
4848                     if (mIpClient == null) {
4849                         logd("IpClient is not ready, START_FILS_CONNECTION dropped");
4850                         break;
4851                     }
4852                     mWifiMetrics.incrementConnectRequestWithFilsAkmCount();
4853                     List<Layer2PacketParcelable> packets;
4854                     packets = (List<Layer2PacketParcelable>) message.obj;
4855                     if (mVerboseLoggingEnabled) {
4856                         Log.d(getTag(), "Send HLP IEs to supplicant");
4857                     }
4858                     addLayer2PacketsToHlpReq(packets);
4859                     WifiConfiguration config = mTargetWifiConfiguration;
4860                     connectToNetwork(config);
4861                     break;
4862                 }
4863                 case CMD_CONNECT_NETWORK: {
4864                     ConnectNetworkMessage cnm = (ConnectNetworkMessage) message.obj;
4865                     if (mIpClient == null) {
4866                         logd("IpClient is not ready, CONNECT_NETWORK dropped");
4867                         cnm.listener.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
4868                         break;
4869                     }
4870                     NetworkUpdateResult result = cnm.result;
4871                     int netId = result.getNetworkId();
4872                     connectToUserSelectNetwork(
4873                             netId, message.sendingUid, result.hasCredentialChanged(),
4874                             cnm.packageName, cnm.attributionTag);
4875                     mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CONNECT_NETWORK,
4876                             mWifiConfigManager.getConfiguredNetwork(netId));
4877                     cnm.listener.sendSuccess();
4878                     break;
4879                 }
4880                 case CMD_SAVE_NETWORK: {
4881                     ConnectNetworkMessage cnm = (ConnectNetworkMessage) message.obj;
4882                     if (mIpClient == null) {
4883                         logd("IpClient is not ready, SAVE_NETWORK dropped");
4884                         cnm.listener.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
4885                         break;
4886                     }
4887                     NetworkUpdateResult result = cnm.result;
4888                     int netId = result.getNetworkId();
4889                     if (mWifiInfo.getNetworkId() == netId) {
4890                         if (result.hasCredentialChanged()) {
4891                             // The network credentials changed and we're connected to this network,
4892                             // start a new connection with the updated credentials.
4893                             logi("CMD_SAVE_NETWORK credential changed for nid="
4894                                     + netId + ". Reconnecting.");
4895                             startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
4896                         } else {
4897                             if (result.hasProxyChanged()) {
4898                                 if (mIpClient != null) {
4899                                     log("Reconfiguring proxy on connection");
4900                                     WifiConfiguration currentConfig =
4901                                             getConnectedWifiConfigurationInternal();
4902                                     if (currentConfig != null) {
4903                                         mIpClient.setHttpProxy(currentConfig.getHttpProxy());
4904                                     } else {
4905                                         Log.w(getTag(),
4906                                                 "CMD_SAVE_NETWORK proxy change - but no current "
4907                                                         + "Wi-Fi config");
4908                                     }
4909                                 }
4910                             }
4911                             if (result.hasIpChanged()) {
4912                                 // The current connection configuration was changed
4913                                 // We switched from DHCP to static or from static to DHCP, or the
4914                                 // static IP address has changed.
4915                                 log("Reconfiguring IP on connection");
4916                                 WifiConfiguration currentConfig =
4917                                         getConnectedWifiConfigurationInternal();
4918                                 if (currentConfig != null) {
4919                                     transitionTo(mL3ProvisioningState);
4920                                 } else {
4921                                     Log.w(getTag(), "CMD_SAVE_NETWORK Ip change - but no current "
4922                                             + "Wi-Fi config");
4923                                 }
4924                             }
4925                         }
4926                     } else if (mWifiInfo.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID
4927                             && result.hasCredentialChanged()) {
4928                         logi("CMD_SAVE_NETWORK credential changed for nid="
4929                                 + netId + " while disconnected. Connecting.");
4930                         WifiConfiguration config =
4931                                 mWifiConfigManager.getConfiguredNetwork(netId);
4932                         if (!mWifiPermissionsUtil.isAdminRestrictedNetwork(config)
4933                                 && !mWifiGlobals.isDeprecatedSecurityTypeNetwork(config)) {
4934                             startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
4935                         }
4936                     } else if (result.hasCredentialChanged()) {
4937                         WifiConfiguration currentConfig =
4938                                 getConnectedWifiConfigurationInternal();
4939                         WifiConfiguration updatedConfig =
4940                                 mWifiConfigManager.getConfiguredNetwork(netId);
4941                         if (currentConfig != null && currentConfig.isLinked(updatedConfig)) {
4942                             logi("current network linked config saved, update linked networks");
4943                             updateLinkedNetworks(currentConfig);
4944                         }
4945                     }
4946                     cnm.listener.sendSuccess();
4947                     break;
4948                 }
4949                 case CMD_BLUETOOTH_CONNECTION_STATE_CHANGE: {
4950                     mWifiNative.setBluetoothCoexistenceScanMode(
4951                             mInterfaceName, mWifiGlobals.isBluetoothConnected());
4952                     break;
4953                 }
4954                 case CMD_SET_SUSPEND_OPT_ENABLED: {
4955                     if (message.arg1 == 1) {
4956                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
4957                         if (message.arg2 == 1) {
4958                             mSuspendWakeLock.release();
4959                         }
4960                     } else {
4961                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
4962                     }
4963                     break;
4964                 }
4965                 case WifiMonitor.ANQP_DONE_EVENT: {
4966                     mPasspointManager.notifyANQPDone((AnqpEvent) message.obj);
4967                     break;
4968                 }
4969                 case CMD_STOP_IP_PACKET_OFFLOAD: {
4970                     int slot = message.arg1;
4971                     int ret = stopWifiIPPacketOffload(slot);
4972                     if (mNetworkAgent != null) {
4973                         mNetworkAgent.sendSocketKeepaliveEvent(slot, ret);
4974                     }
4975                     break;
4976                 }
4977                 case WifiMonitor.RX_HS20_ANQP_ICON_EVENT: {
4978                     mPasspointManager.notifyIconDone((IconEvent) message.obj);
4979                     break;
4980                 }
4981                 case WifiMonitor.HS20_DEAUTH_IMMINENT_EVENT:
4982                     mPasspointManager.handleDeauthImminentEvent((WnmData) message.obj,
4983                             getConnectedWifiConfigurationInternal());
4984                     break;
4985                 case WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT:
4986                     mWifiMetrics
4987                             .incrementTotalNumberOfPasspointConnectionsWithTermsAndConditionsUrl();
4988                     mTermsAndConditionsUrl = mPasspointManager
4989                             .handleTermsAndConditionsEvent((WnmData) message.obj,
4990                             getConnectedWifiConfigurationInternal());
4991                     if (mTermsAndConditionsUrl == null) {
4992                         loge("Disconnecting from Passpoint network due to an issue with the "
4993                                 + "Terms and Conditions URL");
4994                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_PASSPOINT_TAC;
4995                         sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_PASSPOINT_TAC);
4996                     }
4997                     break;
4998                 case WifiMonitor.HS20_REMEDIATION_EVENT:
4999                     mPasspointManager.receivedWnmFrame((WnmData) message.obj);
5000                     break;
5001                 case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE: {
5002                     handleBssTransitionRequest((BtmFrameData) message.obj);
5003                     break;
5004                 }
5005                 case CMD_CONFIG_ND_OFFLOAD: {
5006                     if (!isFromCurrentIpClientCallbacks(message)) break;
5007                     final boolean enabled = (message.arg2 > 0);
5008                     mWifiNative.configureNeighborDiscoveryOffload(mInterfaceName, enabled);
5009                     break;
5010                 }
5011                 // Link configuration (IP address, DNS, ...) changes notified via netlink
5012                 case CMD_UPDATE_LINKPROPERTIES: {
5013                     if (!isFromCurrentIpClientCallbacks(message)) break;
5014                     updateLinkProperties((LinkProperties) message.obj);
5015                     break;
5016                 }
5017                 case CMD_START_IP_PACKET_OFFLOAD:
5018                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF:
5019                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
5020                     if (mNetworkAgent != null) {
5021                         mNetworkAgent.sendSocketKeepaliveEvent(message.arg1,
5022                                 SocketKeepalive.ERROR_INVALID_NETWORK);
5023                     }
5024                     break;
5025                 }
5026                 case CMD_INSTALL_PACKET_FILTER: {
5027                     if (!isFromCurrentIpClientCallbacks(message)) break;
5028                     if (mContext.getResources().getBoolean(
5029                             R.bool.config_wifiEnableApfOnNonPrimarySta)
5030                             || isPrimary()) {
5031                         mWifiNative.installPacketFilter(mInterfaceName, (byte[]) message.obj);
5032                     } else {
5033                         Log.i(TAG, "Not applying packet filter on non primary CMM");
5034                     }
5035                     break;
5036                 }
5037                 case CMD_READ_PACKET_FILTER: {
5038                     if (!isFromCurrentIpClientCallbacks(message)) break;
5039                     byte[] packetFilter = null;
5040                     if (mContext.getResources().getBoolean(
5041                             R.bool.config_wifiEnableApfOnNonPrimarySta)
5042                             || isPrimary()) {
5043                         packetFilter = mWifiNative.readPacketFilter(mInterfaceName);
5044                     } else {
5045                         Log.v(TAG, "APF not supported on non primary CMM - return null");
5046                     }
5047                     if (mIpClient != null) {
5048                         mIpClient.readPacketFilterComplete(packetFilter);
5049                     }
5050                     break;
5051                 }
5052                 case CMD_SET_FALLBACK_PACKET_FILTERING: {
5053                     if (!isFromCurrentIpClientCallbacks(message)) break;
5054                     if ((boolean) message.obj) {
5055                         mWifiNative.startFilteringMulticastV4Packets(mInterfaceName);
5056                     } else {
5057                         mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName);
5058                     }
5059                     break;
5060                 }
5061                 case CMD_SET_MAX_DTIM_MULTIPLIER: {
5062                     if (!isFromCurrentIpClientCallbacks(message)) break;
5063                     final int maxMultiplier = message.arg2;
5064                     final boolean success =
5065                             mWifiNative.setDtimMultiplier(mInterfaceName, maxMultiplier);
5066                     if (mVerboseLoggingEnabled) {
5067                         Log.d(TAG, "Set maximum DTIM Multiplier to " + maxMultiplier
5068                                 + (success ? " SUCCESS" : " FAIL"));
5069                     }
5070                     break;
5071                 }
5072                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
5073                 case CMD_RESET_SIM_NETWORKS:
5074                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5075                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5076                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5077                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5078                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5079                 case CMD_RSSI_POLL:
5080                 case CMD_ONESHOT_RSSI_POLL:
5081                 case CMD_PRE_DHCP_ACTION:
5082                 case CMD_PRE_DHCP_ACTION_COMPLETE:
5083                 case CMD_POST_DHCP_ACTION:
5084                 case WifiMonitor.SUP_REQUEST_IDENTITY:
5085                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5086                 case WifiMonitor.TARGET_BSSID_EVENT:
5087                 case WifiMonitor.ASSOCIATED_BSSID_EVENT:
5088                 case WifiMonitor.TRANSITION_DISABLE_INDICATION:
5089                 case CMD_UNWANTED_NETWORK:
5090                 case CMD_CONNECTING_WATCHDOG_TIMER:
5091                 case WifiMonitor.NETWORK_NOT_FOUND_EVENT:
5092                 case CMD_ROAM_WATCHDOG_TIMER: {
5093                     // no-op: all messages must be handled in the base state in case it was missed
5094                     // in one of the child states.
5095                     break;
5096                 }
5097                 case CMD_ACCEPT_EAP_SERVER_CERTIFICATE:
5098                     // If TOFU is not supported, then we are already connected
5099                     if (!isTrustOnFirstUseSupported()) break;
5100                     // Got an approval for a TOFU network. Disconnect (if connected) and trigger
5101                     // a connection to the new approved network.
5102                     logd("User accepted TOFU provided certificate");
5103                     startConnectToNetwork(message.arg1, Process.WIFI_UID, SUPPLICANT_BSSID_ANY);
5104                     break;
5105                 case CMD_REJECT_EAP_INSECURE_CONNECTION:
5106                 case CMD_START_ROAM:
5107                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
5108                 case CMD_IP_CONFIGURATION_LOST:
5109                 case CMD_IP_REACHABILITY_LOST:
5110                 case CMD_IP_REACHABILITY_FAILURE: {
5111                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5112                     break;
5113                 }
5114                 case 0: {
5115                     // We want to notice any empty messages (with what == 0) that might crop up.
5116                     // For example, we may have recycled a message sent to multiple handlers.
5117                     Log.wtf(getTag(), "Error! empty message encountered");
5118                     break;
5119                 }
5120                 default: {
5121                     loge("Error! unhandled message" + message);
5122                     break;
5123                 }
5124             }
5125 
5126             logStateAndMessage(message, this);
5127             return HANDLED;
5128         }
5129     }
5130 
handleL3MessagesWhenNotConnected(Message message)5131     private boolean handleL3MessagesWhenNotConnected(Message message) {
5132         boolean handleStatus = HANDLED;
5133 
5134         if (!mIpClientWithPreConnection) {
5135             return NOT_HANDLED;
5136         }
5137 
5138         switch (message.what) {
5139             case CMD_PRE_DHCP_ACTION:
5140                 if (!isFromCurrentIpClientCallbacks(message)) break;
5141                 handlePreDhcpSetup();
5142                 break;
5143             case CMD_PRE_DHCP_ACTION_COMPLETE:
5144                 if (mIpClient != null) {
5145                     mIpClient.completedPreDhcpAction();
5146                 }
5147                 break;
5148             case CMD_IPV4_PROVISIONING_FAILURE:
5149                 stopDhcpSetup();
5150                 deferMessage(message);
5151                 break;
5152             case CMD_POST_DHCP_ACTION:
5153             case CMD_IPV4_PROVISIONING_SUCCESS:
5154             case CMD_IP_CONFIGURATION_SUCCESSFUL:
5155                 deferMessage(message);
5156                 break;
5157             default:
5158                 return NOT_HANDLED;
5159         }
5160 
5161         return handleStatus;
5162     }
5163 
createNetworkAgentSpecifier( @onNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid, boolean matchLocationSensitiveInformation)5164     private WifiNetworkAgentSpecifier createNetworkAgentSpecifier(
5165             @NonNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid,
5166             boolean matchLocationSensitiveInformation) {
5167         // Defensive copy to avoid mutating the passed argument
5168         final WifiConfiguration conf = new WifiConfiguration(currentWifiConfiguration);
5169         conf.BSSID = currentBssid;
5170 
5171         int band = WifiNetworkSpecifier.getBand(mWifiInfo.getFrequency());
5172 
5173         if (!isPrimary() && mWifiGlobals.isSupportMultiInternetDual5G()
5174                 && band == ScanResult.WIFI_BAND_5_GHZ) {
5175             if (mWifiInfo.getFrequency() <= ScanResult.BAND_5_GHZ_LOW_HIGHEST_FREQ_MHZ) {
5176                 band = ScanResult.WIFI_BAND_5_GHZ_LOW;
5177             } else {
5178                 band = ScanResult.WIFI_BAND_5_GHZ_HIGH;
5179             }
5180         }
5181 
5182         WifiNetworkAgentSpecifier wns =
5183                 new WifiNetworkAgentSpecifier(conf, band, matchLocationSensitiveInformation);
5184         return wns;
5185     }
5186 
getCapabilities( WifiConfiguration currentWifiConfiguration, String currentBssid)5187     private NetworkCapabilities getCapabilities(
5188             WifiConfiguration currentWifiConfiguration, String currentBssid) {
5189         final NetworkCapabilities.Builder builder =
5190                 new NetworkCapabilities.Builder(mNetworkCapabilitiesFilter);
5191         // MatchAllNetworkSpecifier set in the mNetworkCapabilitiesFilter should never be set in the
5192         // agent's specifier.
5193         builder.setNetworkSpecifier(null);
5194         if (currentWifiConfiguration == null) {
5195             return builder.build();
5196         }
5197 
5198         if (mWifiInfo.isTrusted()) {
5199             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5200         } else {
5201             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5202         }
5203 
5204         if (mWifiInfo.isRestricted()) {
5205             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
5206         }
5207 
5208         if (SdkLevel.isAtLeastS()) {
5209             if (mWifiInfo.isOemPaid()) {
5210                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID);
5211                 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
5212             } else {
5213                 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID);
5214             }
5215             if (mWifiInfo.isOemPrivate()) {
5216                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE);
5217                 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
5218             } else {
5219                 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE);
5220             }
5221         }
5222 
5223         builder.setOwnerUid(currentWifiConfiguration.creatorUid);
5224         builder.setAdministratorUids(new int[]{currentWifiConfiguration.creatorUid});
5225         if (SdkLevel.isAtLeastT()) {
5226             builder.setAllowedUids(Set.of(currentWifiConfiguration.creatorUid));
5227         }
5228 
5229         if (!WifiConfiguration.isMetered(currentWifiConfiguration, mWifiInfo)) {
5230             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5231         } else {
5232             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5233         }
5234 
5235         if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI) {
5236             builder.setSignalStrength(mWifiInfo.getRssi());
5237         } else {
5238             builder.setSignalStrength(NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
5239         }
5240 
5241         if (currentWifiConfiguration.osu) {
5242             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
5243         }
5244 
5245         if (!WifiManager.UNKNOWN_SSID.equals(mWifiInfo.getSSID())) {
5246             builder.setSsid(mWifiInfo.getSSID());
5247         }
5248 
5249         // Only send out WifiInfo in >= Android S devices.
5250         if (SdkLevel.isAtLeastS()) {
5251             builder.setTransportInfo(new WifiInfo(mWifiInfo));
5252 
5253             if (mWifiInfo.getSubscriptionId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID
5254                     && mWifiInfo.isCarrierMerged()) {
5255                 builder.setSubscriptionIds(Collections.singleton(mWifiInfo.getSubscriptionId()));
5256             }
5257         }
5258 
5259         List<Integer> uids = new ArrayList<>(mNetworkFactory
5260                 .getSpecificNetworkRequestUids(
5261                         currentWifiConfiguration, currentBssid));
5262         // There is an active local only specific request.
5263         if (!uids.isEmpty()) {
5264             // Remove internet capability.
5265             if (!mNetworkFactory.shouldHaveInternetCapabilities()) {
5266                 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
5267             }
5268             if (SdkLevel.isAtLeastS()) {
5269                 builder.setUids(getUidRangeSet(uids));
5270             } else {
5271                 // Use requestor Uid and PackageName on pre-S device.
5272                 Pair<Integer, String> specificRequestUidAndPackageName = mNetworkFactory
5273                         .getSpecificNetworkRequestUidAndPackageName(currentWifiConfiguration,
5274                                 currentBssid);
5275                 // Fill up the uid/packageName for this connection.
5276                 builder.setRequestorUid(specificRequestUidAndPackageName.first);
5277                 builder.setRequestorPackageName(specificRequestUidAndPackageName.second);
5278             }
5279             // Fill up the network agent specifier for this connection, allowing NetworkCallbacks
5280             // to match local-only specifiers in requests. TODO(b/187921303): a third-party app can
5281             // observe this location-sensitive information by registering a NetworkCallback.
5282             builder.setNetworkSpecifier(createNetworkAgentSpecifier(currentWifiConfiguration,
5283                     getConnectedBssidInternal(), true /* matchLocalOnlySpecifiers */));
5284         } else {
5285             // Fill up the network agent specifier for this connection, without allowing
5286             // NetworkCallbacks to match local-only specifiers in requests.
5287             builder.setNetworkSpecifier(createNetworkAgentSpecifier(currentWifiConfiguration,
5288                     getConnectedBssidInternal(), false /* matchLocalOnlySpecifiers */));
5289         }
5290 
5291         updateLinkBandwidth(builder);
5292         final NetworkCapabilities networkCapabilities = builder.build();
5293         if (mVcnManager == null || !currentWifiConfiguration.carrierMerged
5294                 || !SdkLevel.isAtLeastS()) {
5295             return networkCapabilities;
5296         }
5297         final VcnNetworkPolicyResult vcnNetworkPolicy =
5298                 mVcnManager.applyVcnNetworkPolicy(networkCapabilities, mLinkProperties);
5299         if (vcnNetworkPolicy.isTeardownRequested()) {
5300             mFrameworkDisconnectReasonOverride =
5301                     WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_VNC_REQUEST;
5302             sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_VCN_REQUEST);
5303         }
5304         final NetworkCapabilities vcnCapability = vcnNetworkPolicy.getNetworkCapabilities();
5305         if (!vcnCapability.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)) {
5306             if (mVerboseLoggingEnabled) {
5307                 logd("NET_CAPABILITY_NOT_VCN_MANAGED is removed");
5308             }
5309             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
5310         }
5311         if (!vcnCapability.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
5312             if (mVerboseLoggingEnabled) {
5313                 logd("NET_CAPABILITY_NOT_RESTRICTED is removed");
5314             }
5315             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
5316         }
5317         return builder.build();
5318     }
5319 
getUidRangeSet(List<Integer> uids)5320     private Set<Range<Integer>> getUidRangeSet(List<Integer> uids) {
5321         Collections.sort(uids);
5322         Set<Range<Integer>> uidRanges = new ArraySet<>();
5323         int start = 0;
5324         int next = 0;
5325         for (int i : uids) {
5326             if (start == next) {
5327                 start = i;
5328                 next = start + 1;
5329             } else if (i == next) {
5330                 next++;
5331             } else {
5332                 uidRanges.add(new Range<>(start, next - 1));
5333                 start = i;
5334                 next = start + 1;
5335             }
5336         }
5337         uidRanges.add(new Range<>(start, next - 1));
5338         return uidRanges;
5339     }
5340 
updateLinkBandwidth(NetworkCapabilities.Builder networkCapabilitiesBuilder)5341     private void updateLinkBandwidth(NetworkCapabilities.Builder networkCapabilitiesBuilder) {
5342         int txTputKbps = 0;
5343         int rxTputKbps = 0;
5344         int currRssi = mWifiInfo.getRssi();
5345         if (currRssi != WifiInfo.INVALID_RSSI) {
5346             WifiScoreCard.PerNetwork network = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
5347             txTputKbps = network.getTxLinkBandwidthKbps();
5348             rxTputKbps = network.getRxLinkBandwidthKbps();
5349         } else {
5350             // Fall back to max link speed. This should rarely happen if ever
5351             int maxTxLinkSpeedMbps = mWifiInfo.getMaxSupportedTxLinkSpeedMbps();
5352             int maxRxLinkSpeedMbps = mWifiInfo.getMaxSupportedRxLinkSpeedMbps();
5353             txTputKbps = maxTxLinkSpeedMbps * 1000;
5354             rxTputKbps = maxRxLinkSpeedMbps * 1000;
5355         }
5356         if (mVerboseLoggingEnabled) {
5357             logd("reported txKbps " + txTputKbps + " rxKbps " + rxTputKbps);
5358         }
5359         if (txTputKbps > 0) {
5360             networkCapabilitiesBuilder.setLinkUpstreamBandwidthKbps(txTputKbps);
5361         }
5362         if (rxTputKbps > 0) {
5363             networkCapabilitiesBuilder.setLinkDownstreamBandwidthKbps(rxTputKbps);
5364         }
5365     }
5366 
5367     /**
5368      * Method to update network capabilities from the current WifiConfiguration.
5369      */
5370     @Override
updateCapabilities()5371     public void updateCapabilities() {
5372         updateCapabilities(getConnectedWifiConfigurationInternal());
5373     }
5374 
5375     /**
5376      * Check if BSSID belongs to any of the affiliated link BSSID's.
5377      * @param bssid BSSID of the AP.
5378      * @return true if BSSID matches to one of the affiliated link BSSIDs, false otherwise.
5379      */
isAffiliatedLinkBssid(@onNull MacAddress bssid)5380     public boolean isAffiliatedLinkBssid(@NonNull MacAddress bssid) {
5381         List<MloLink> links = mWifiInfo.getAffiliatedMloLinks();
5382         for (MloLink link: links) {
5383             if (bssid.equals(link.getApMacAddress())) {
5384                 return true;
5385             }
5386         }
5387         return false;
5388     }
5389 
5390     /**
5391      * Check if the connection is MLO (Multi-Link Operation).
5392      * @return true if connection is MLO, otherwise false.
5393      */
isMlo()5394     public boolean isMlo() {
5395         return !mWifiInfo.getAssociatedMloLinks().isEmpty();
5396     }
5397 
updateCapabilities(WifiConfiguration currentWifiConfiguration)5398     private void updateCapabilities(WifiConfiguration currentWifiConfiguration) {
5399         updateCapabilities(getCapabilities(currentWifiConfiguration, getConnectedBssidInternal()));
5400     }
5401 
updateCapabilities(NetworkCapabilities networkCapabilities)5402     private void updateCapabilities(NetworkCapabilities networkCapabilities) {
5403         if (mNetworkAgent == null) {
5404             return;
5405         }
5406         mNetworkAgent.sendNetworkCapabilitiesAndCache(networkCapabilities);
5407     }
5408 
handleEapAuthFailure(int networkId, int errorCode)5409     private void handleEapAuthFailure(int networkId, int errorCode) {
5410         WifiConfiguration targetedNetwork =
5411                 mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
5412         if (targetedNetwork != null) {
5413             switch (targetedNetwork.enterpriseConfig.getEapMethod()) {
5414                 case WifiEnterpriseConfig.Eap.SIM:
5415                 case WifiEnterpriseConfig.Eap.AKA:
5416                 case WifiEnterpriseConfig.Eap.AKA_PRIME:
5417                     if (errorCode == WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED) {
5418                         mWifiCarrierInfoManager.resetCarrierKeysForImsiEncryption(targetedNetwork);
5419                     } else {
5420                         int carrierId = targetedNetwork.carrierId;
5421                         if (mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(carrierId)) {
5422                             mWifiPseudonymManager.retrieveOobPseudonymWithRateLimit(carrierId);
5423                         }
5424                     }
5425                     break;
5426 
5427                 default:
5428                     // Do Nothing
5429             }
5430         }
5431     }
5432 
5433     /**
5434      * All callbacks are triggered on the main Wifi thread.
5435      * See {@link WifiNetworkAgent#WifiNetworkAgent}'s looper argument in
5436      * {@link WifiInjector#makeWifiNetworkAgent}.
5437      */
5438     private class WifiNetworkAgentCallback implements WifiNetworkAgent.Callback {
5439         private int mLastNetworkStatus = -1; // To detect when the status really changes
5440 
isThisCallbackActive()5441         private boolean isThisCallbackActive() {
5442             return mNetworkAgent != null && mNetworkAgent.getCallback() == this;
5443         }
5444 
5445         @Override
onNetworkUnwanted()5446         public void onNetworkUnwanted() {
5447             // Ignore if we're not the current networkAgent.
5448             if (!isThisCallbackActive()) return;
5449             if (mVerboseLoggingEnabled) {
5450                 logd("WifiNetworkAgent -> Wifi unwanted score " + mWifiInfo.getScore());
5451             }
5452             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
5453         }
5454 
5455         @Override
onValidationStatus(int status, @Nullable Uri redirectUri)5456         public void onValidationStatus(int status, @Nullable Uri redirectUri) {
5457             if (!isThisCallbackActive()) return;
5458             if (status == mLastNetworkStatus) return;
5459             mLastNetworkStatus = status;
5460             if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID) {
5461                 if (mVerboseLoggingEnabled) {
5462                     logd("WifiNetworkAgent -> Wifi networkStatus invalid, score="
5463                             + mWifiInfo.getScore());
5464                 }
5465                 unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
5466             } else if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
5467                 if (mVerboseLoggingEnabled) {
5468                     logd("WifiNetworkAgent -> Wifi networkStatus valid, score= "
5469                             + mWifiInfo.getScore());
5470                 }
5471                 mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
5472                 doNetworkStatus(status);
5473             }
5474             boolean captivePortalDetected = redirectUri != null
5475                     && redirectUri.toString() != null
5476                     && redirectUri.toString().length() > 0;
5477             if (captivePortalDetected) {
5478                 Log.i(getTag(), "Captive Portal detected, status=" + status
5479                         + ", redirectUri=" + redirectUri);
5480                 mWifiConfigManager.noteCaptivePortalDetected(mWifiInfo.getNetworkId());
5481                 mCmiMonitor.onCaptivePortalDetected(mClientModeManager);
5482                 mCurrentConnectionDetectedCaptivePortal = true;
5483             }
5484         }
5485 
5486         @Override
onSaveAcceptUnvalidated(boolean accept)5487         public void onSaveAcceptUnvalidated(boolean accept) {
5488             if (!isThisCallbackActive()) return;
5489             ClientModeImpl.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
5490         }
5491 
5492         @Override
onStartSocketKeepalive(int slot, @NonNull Duration interval, @NonNull KeepalivePacketData packet)5493         public void onStartSocketKeepalive(int slot, @NonNull Duration interval,
5494                 @NonNull KeepalivePacketData packet) {
5495             if (!isThisCallbackActive()) return;
5496             ClientModeImpl.this.sendMessage(
5497                     CMD_START_IP_PACKET_OFFLOAD, slot, (int) interval.getSeconds(), packet);
5498         }
5499 
5500         @Override
onStopSocketKeepalive(int slot)5501         public void onStopSocketKeepalive(int slot) {
5502             if (!isThisCallbackActive()) return;
5503             ClientModeImpl.this.sendMessage(CMD_STOP_IP_PACKET_OFFLOAD, slot);
5504         }
5505 
5506         @Override
onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet)5507         public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) {
5508             if (!isThisCallbackActive()) return;
5509             ClientModeImpl.this.sendMessage(
5510                     CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0, packet);
5511         }
5512 
5513         @Override
onRemoveKeepalivePacketFilter(int slot)5514         public void onRemoveKeepalivePacketFilter(int slot) {
5515             if (!isThisCallbackActive()) return;
5516             ClientModeImpl.this.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot);
5517         }
5518 
5519         @Override
onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)5520         public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
5521             if (!isThisCallbackActive()) return;
5522             // Enable RSSI monitoring only on primary STA
5523             if (!isPrimary()) {
5524                 return;
5525             }
5526             mWifiThreadRunner.post(
5527                     () -> mRssiMonitor.updateAppThresholdsAndStartMonitor(thresholds),
5528                     TAG + "#onSignalStrengthThresholdsUpdated");
5529         }
5530 
5531         @Override
onAutomaticReconnectDisabled()5532         public void onAutomaticReconnectDisabled() {
5533             if (!isThisCallbackActive()) return;
5534             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
5535         }
5536 
5537         @Override
onDscpPolicyStatusUpdated(int policyId, int status)5538         public void onDscpPolicyStatusUpdated(int policyId, int status) {
5539             mQosPolicyRequestHandler.setQosPolicyStatus(policyId, status);
5540         }
5541     }
5542 
5543     @Override
onDeviceMobilityStateUpdated(@eviceMobilityState int newState)5544     public void onDeviceMobilityStateUpdated(@DeviceMobilityState int newState) {
5545         if (!mScreenOn) {
5546             return;
5547         }
5548         if (isPrimary()) {
5549             mRssiMonitor.updatePollRssiInterval(newState);
5550         }
5551     }
5552 
5553     @Override
setLinkLayerStatsPollingInterval(int newIntervalMs)5554     public void setLinkLayerStatsPollingInterval(int newIntervalMs) {
5555         mRssiMonitor.overridePollRssiInterval(newIntervalMs);
5556     }
5557 
isNewConnectionInProgress(@onNull String disconnectingSsid)5558     private boolean isNewConnectionInProgress(@NonNull String disconnectingSsid) {
5559         String targetSsid = getConnectingSsidInternal();
5560         // If network is removed while connecting, targetSsid can be null.
5561         if (targetSsid == null) {
5562             return false;
5563         }
5564         // When connecting to another network while already connected, the old network will first
5565         // disconnect before the new connection can begin. Thus, the presence of a mLastNetworkId
5566         // that's different from the mTargetNetworkId indicates that this network disconnection is
5567         // triggered for the previously connected network as opposed to the current ongoing
5568         // connection.
5569         boolean isConnectingWhileAlreadyConnected =
5570                 mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
5571                 && mLastNetworkId != mTargetNetworkId;
5572 
5573         // This second condition is needed to catch cases where 2 simultaneous connections happen
5574         // back-to-back. When a new connection start before the previous one finishes, the
5575         // previous network will get removed from the supplicant and cause a disconnect message
5576         // to be received with the previous network's SSID. Thus, if the disconnecting SSID does not
5577         // match the target SSID, it means a new connection is in progress.
5578         boolean isConnectingToAnotherNetwork = !disconnectingSsid.equals(targetSsid);
5579         return isConnectingWhileAlreadyConnected || isConnectingToAnotherNetwork;
5580     }
5581 
unwantedNetwork(int reason)5582     private void unwantedNetwork(int reason) {
5583         sendMessage(CMD_UNWANTED_NETWORK, reason);
5584     }
5585 
doNetworkStatus(int status)5586     private void doNetworkStatus(int status) {
5587         sendMessage(CMD_NETWORK_STATUS, status);
5588     }
5589 
updatePseudonymFromOob(int carrierId, String pseudonym)5590     private void updatePseudonymFromOob(int carrierId, String pseudonym) {
5591         sendMessage(CMD_UPDATE_OOB_PSEUDONYM, carrierId, 0, pseudonym);
5592     }
5593 
5594     class ConnectingOrConnectedState extends RunnerState {
ConnectingOrConnectedState(int threshold)5595         ConnectingOrConnectedState(int threshold) {
5596             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
5597         }
5598 
5599         @Override
enterImpl()5600         public void enterImpl() {
5601             if (mVerboseLoggingEnabled) Log.v(getTag(), "Entering ConnectingOrConnectedState");
5602             mCmiMonitor.onConnectionStart(mClientModeManager);
5603         }
5604 
5605         @Override
exitImpl()5606         public void exitImpl() {
5607             if (mVerboseLoggingEnabled) Log.v(getTag(), "Exiting ConnectingOrConnectedState");
5608             mCmiMonitor.onConnectionEnd(mClientModeManager);
5609 
5610             // Not connected/connecting to any network:
5611             // 1. Disable the network in supplicant to prevent it from auto-connecting. We don't
5612             // remove the network to avoid losing any cached info in supplicant (reauth, etc) in
5613             // case we reconnect back to the same network.
5614             // 2. Set a random MAC address to ensure that we're not leaking the MAC address.
5615             mWifiNative.disableNetwork(mInterfaceName);
5616             if (mWifiGlobals.isConnectedMacRandomizationEnabled()) {
5617                 mFailedToResetMacAddress = !mWifiNative.setStaMacAddress(
5618                         mInterfaceName, MacAddressUtils.createRandomUnicastAddress());
5619                 if (mFailedToResetMacAddress) {
5620                     Log.e(getTag(), "Failed to set random MAC address on disconnect");
5621                 }
5622             }
5623             if (mWifiInfo.getBSSID() != null) {
5624                 mWifiBlocklistMonitor.removeAffiliatedBssids(mWifiInfo.getBSSID());
5625             }
5626             mWifiInfo.reset();
5627             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
5628             mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
5629             updateCurrentConnectionInfo();
5630 
5631             // For secondary client roles, they should stop themselves upon disconnection.
5632             // - Primary role shouldn't because it is persistent, and should try connecting to other
5633             //   networks upon disconnection.
5634             // - ROLE_CLIENT_LOCAL_ONLY shouldn't because it has auto-retry logic if the connection
5635             //   fails. WifiNetworkFactory will explicitly remove the CMM when the request is
5636             //   complete.
5637             // TODO(b/160346062): Maybe clean this up by having ClientModeManager register a
5638             //  onExitConnectingOrConnectedState() callback with ClientModeImpl and implementing
5639             //  this logic in ClientModeManager. ClientModeImpl should be role-agnostic.
5640             ClientRole role = mClientModeManager.getRole();
5641             if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED
5642                     || role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
5643                 if (mVerboseLoggingEnabled) {
5644                     Log.d(getTag(), "Disconnected in ROLE_CLIENT_SECONDARY_*, "
5645                             + "stop ClientModeManager=" + mClientModeManager);
5646                 }
5647                 // stop owner ClientModeManager, which will in turn stop this ClientModeImpl
5648                 mClientModeManager.stop();
5649             }
5650         }
5651 
5652         @Override
getMessageLogRec(int what)5653         public String getMessageLogRec(int what) {
5654             return ClientModeImpl.class.getSimpleName() + "."
5655                     + ConnectingOrConnectedState.class.getSimpleName() + "." + getWhatToString(
5656                     what);
5657         }
5658 
5659         @Override
processMessageImpl(Message message)5660         public boolean processMessageImpl(Message message) {
5661             boolean handleStatus = HANDLED;
5662             switch (message.what) {
5663                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: {
5664                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5665                     SupplicantState state = handleSupplicantStateChange(stateChangeResult);
5666                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
5667                     // when authentication times out after a successful connection,
5668                     // we can figure this from the supplicant state. If supplicant
5669                     // state is DISCONNECTED, but the agent is not disconnected, we
5670                     // need to handle a disconnection
5671                     if (mVerboseLoggingEnabled) {
5672                         log("ConnectingOrConnectedState: Supplicant State change "
5673                                 + stateChangeResult);
5674                     }
5675                     @SupplicantEventCode int supplicantEvent;
5676                     switch (stateChangeResult.state) {
5677                         case COMPLETED:
5678                             supplicantEvent = SupplicantStaIfaceHal.SUPPLICANT_EVENT_CONNECTED;
5679                             break;
5680                         case ASSOCIATING:
5681                             supplicantEvent = SupplicantStaIfaceHal.SUPPLICANT_EVENT_ASSOCIATING;
5682                             break;
5683                         case ASSOCIATED:
5684                             supplicantEvent = SupplicantStaIfaceHal.SUPPLICANT_EVENT_ASSOCIATED;
5685                             break;
5686                         default:
5687                             supplicantEvent = -1;
5688                     }
5689                     if (supplicantEvent != -1) {
5690                         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(
5691                                     stateChangeResult.networkId);
5692                         try {
5693                             logEventIfManagedNetwork(config, supplicantEvent,
5694                                     MacAddress.fromString(stateChangeResult.bssid), "");
5695                         } catch (IllegalArgumentException e) {
5696                             Log.i(TAG, "Invalid bssid received for state change event");
5697                         }
5698                     }
5699                     if (state == SupplicantState.DISCONNECTED && mNetworkAgent != null) {
5700                         if (mVerboseLoggingEnabled) {
5701                             log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
5702                         }
5703                         handleNetworkDisconnect(false,
5704                                 WIFI_DISCONNECT_REPORTED__FAILURE_CODE__SUPPLICANT_DISCONNECTED);
5705                         transitionTo(mDisconnectedState);
5706                     }
5707                     if (state == SupplicantState.COMPLETED) {
5708                         mWifiScoreReport.noteIpCheck();
5709                     }
5710                     break;
5711                 }
5712                 case WifiMonitor.ASSOCIATED_BSSID_EVENT: {
5713                     // This is where we can confirm the connection BSSID. Use it to find the
5714                     // right ScanDetail to populate metrics.
5715                     String someBssid = (String) message.obj;
5716                     if (someBssid != null) {
5717                         // Get the ScanDetail associated with this BSSID.
5718                         ScanDetailCache scanDetailCache =
5719                                 mWifiConfigManager.getScanDetailCacheForNetwork(mTargetNetworkId);
5720                         if (scanDetailCache != null) {
5721                             mWifiMetrics.setConnectionScanDetail(mInterfaceName,
5722                                     scanDetailCache.getScanDetail(someBssid));
5723                         }
5724                         // Update last associated BSSID
5725                         mLastBssid = someBssid;
5726                     }
5727                     handleStatus = NOT_HANDLED;
5728                     break;
5729                 }
5730                 case WifiMonitor.NETWORK_CONNECTION_EVENT: {
5731                     if (mVerboseLoggingEnabled) log("Network connection established");
5732                     NetworkConnectionEventInfo connectionInfo =
5733                             (NetworkConnectionEventInfo) message.obj;
5734                     mLastNetworkId = connectionInfo.networkId;
5735                     mSentHLPs = connectionInfo.isFilsConnection;
5736                     if (mSentHLPs) mWifiMetrics.incrementL2ConnectionThroughFilsAuthCount();
5737                     mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
5738                     mLastBssid = connectionInfo.bssid;
5739                     // TODO: This check should not be needed after ClientModeImpl refactor.
5740                     // Currently, the last connected network configuration is left in
5741                     // wpa_supplicant, this may result in wpa_supplicant initiating connection
5742                     // to it after a config store reload. Hence the old network Id lookups may not
5743                     // work, so disconnect the network and let network selector reselect a new
5744                     // network.
5745                     WifiConfiguration config = getConnectedWifiConfigurationInternal();
5746                     if (config == null) {
5747                         logw("Connected to unknown networkId " + mLastNetworkId
5748                                 + ", disconnecting...");
5749                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_UNKNOWN_NETWORK;
5750                         sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_UNKNOWN_NETWORK);
5751                         break;
5752                     }
5753                     handleNetworkConnectionEventInfo(config, connectionInfo);
5754                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
5755 
5756                     ScanDetailCache scanDetailCache =
5757                             mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
5758                     ScanResult scanResult = null;
5759                     if (scanDetailCache != null && mLastBssid != null) {
5760                         scanResult = scanDetailCache.getScanResult(mLastBssid);
5761                         if (scanResult != null) {
5762                             mWifiInfo.setFrequency(scanResult.frequency);
5763                         }
5764                     }
5765 
5766                     // We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA'
5767                     if (config.enterpriseConfig != null
5768                             && config.enterpriseConfig.isAuthenticationSimBased()) {
5769                         if (mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(
5770                                 config.carrierId)) {
5771                             if (mVerboseLoggingEnabled) {
5772                                 logd("add PseudonymUpdatingListener");
5773                             }
5774                             mWifiPseudonymManager.registerPseudonymUpdatingListener(
5775                                     mPseudonymUpdatingListener);
5776                         }
5777                         mLastSubId = mWifiCarrierInfoManager.getBestMatchSubscriptionId(config);
5778                         mLastSimBasedConnectionCarrierName =
5779                                 mWifiCarrierInfoManager.getCarrierNameForSubId(mLastSubId);
5780                         String anonymousIdentity =
5781                                 mWifiNative.getEapAnonymousIdentity(mInterfaceName);
5782                         if (!TextUtils.isEmpty(anonymousIdentity)
5783                                 && !WifiCarrierInfoManager
5784                                 .isAnonymousAtRealmIdentity(anonymousIdentity)) {
5785                             String decoratedPseudonym = mWifiCarrierInfoManager
5786                                     .decoratePseudonymWith3GppRealm(config,
5787                                             anonymousIdentity);
5788                             boolean updateToNativeService = false;
5789                             if (decoratedPseudonym != null
5790                                     && !decoratedPseudonym.equals(anonymousIdentity)) {
5791                                 anonymousIdentity = decoratedPseudonym;
5792                                 // propagate to the supplicant to avoid using
5793                                 // the original anonymous identity for firmware
5794                                 // roaming.
5795                                 if (mVerboseLoggingEnabled) {
5796                                     log("Update decorated pseudonym: " + anonymousIdentity);
5797                                 }
5798                                 updateToNativeService = true;
5799                             }
5800                             // This needs native change to avoid disconnecting from the current
5801                             // network. Consider that older releases might not be able to have
5802                             // the vendor partition updated, only update to native service on T
5803                             // or newer.
5804                             if (mWifiNative.isSupplicantAidlServiceVersionAtLeast(1)) {
5805                                 mWifiNative.setEapAnonymousIdentity(mInterfaceName,
5806                                         anonymousIdentity, updateToNativeService);
5807                             }
5808                             if (mVerboseLoggingEnabled) {
5809                                 log("EAP Pseudonym: " + anonymousIdentity);
5810                             }
5811                             // Save the pseudonym only if it is a real one
5812                             config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
5813                             int carrierId = config.carrierId;
5814                             if (mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(
5815                                     carrierId)) {
5816                                 mWifiPseudonymManager.setInBandPseudonym(carrierId,
5817                                         anonymousIdentity);
5818                             }
5819                         } else {
5820                             // Clear any stored pseudonyms
5821                             config.enterpriseConfig.setAnonymousIdentity(null);
5822                         }
5823                         mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
5824                         if (config.isPasspoint()) {
5825                             mPasspointManager.setAnonymousIdentity(config);
5826                         } else if (config.fromWifiNetworkSuggestion) {
5827                             mWifiNetworkSuggestionsManager.setAnonymousIdentity(config);
5828                         }
5829                     }
5830                     // When connecting to Passpoint, ask for the Venue URL
5831                     if (config.isPasspoint()) {
5832                         mTermsAndConditionsUrl = null;
5833                         if (scanResult == null && mLastBssid != null) {
5834                             // The cached scan result of connected network would be null at the
5835                             // first connection, try to check full scan result list again to look up
5836                             // matched scan result associated to the current SSID and BSSID.
5837                             scanResult = mScanRequestProxy.getScanResult(mLastBssid);
5838                         }
5839                         if (scanResult != null) {
5840                             mPasspointManager.requestVenueUrlAnqpElement(scanResult);
5841                         }
5842                     }
5843                     mWifiInfo.setNetworkKey(config.getNetworkKeyFromSecurityType(
5844                             mWifiInfo.getCurrentSecurityType()));
5845                     if (mApplicationQosPolicyRequestHandler.isFeatureEnabled()) {
5846                         mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface(
5847                                 mInterfaceName, mostRecentConnectionSupports11ax());
5848                     }
5849                     mWifiNative.resendMscs(mInterfaceName);
5850                     updateLayer2Information();
5851                     updateCurrentConnectionInfo();
5852                     transitionTo(mL3ProvisioningState);
5853                     break;
5854                 }
5855                 case CMD_UPDATE_OOB_PSEUDONYM: {
5856                     WifiConfiguration config = getConnectedWifiConfigurationInternal();
5857                     if (config == null) {
5858                         log("OOB pseudonym is updated, but no valid connected network.");
5859                         break;
5860                     }
5861                     int updatingCarrierId = message.arg1;
5862                     if (config.enterpriseConfig == null
5863                             || !config.enterpriseConfig.isAuthenticationSimBased()
5864                             || !mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(
5865                                     config.carrierId)
5866                             || updatingCarrierId != config.carrierId) {
5867                         log("OOB pseudonym is not applied.");
5868                         break;
5869                     }
5870                     if (mWifiNative.isSupplicantAidlServiceVersionAtLeast(1)) {
5871                         log("send OOB pseudonym to supplicant");
5872                         String pseudonym = (String) message.obj;
5873                         mWifiNative.setEapAnonymousIdentity(mInterfaceName,
5874                                 mWifiCarrierInfoManager.decoratePseudonymWith3GppRealm(
5875                                         config, pseudonym),
5876                                 /*updateToNativeService=*/ true);
5877                     }
5878                     break;
5879                 }
5880                 case WifiMonitor.SUP_REQUEST_SIM_AUTH: {
5881                     logd("Received SUP_REQUEST_SIM_AUTH");
5882                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5883                     if (requestData != null) {
5884                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5885                             handleGsmAuthRequest(requestData);
5886                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5887                                 || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5888                             handle3GAuthRequest(requestData);
5889                         }
5890                     } else {
5891                         loge("Invalid SIM auth request");
5892                     }
5893                     break;
5894                 }
5895                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: {
5896                     DisconnectEventInfo eventInfo = (DisconnectEventInfo) message.obj;
5897                     if (mVerboseLoggingEnabled) {
5898                         log("ConnectingOrConnectedState: Network disconnection " + eventInfo);
5899                     }
5900                     if (eventInfo.reasonCode
5901                             == StaIfaceReasonCode.FOURWAY_HANDSHAKE_TIMEOUT) {
5902                         String bssid = !isValidBssid(eventInfo.bssid)
5903                                 ? mTargetBssid : eventInfo.bssid;
5904                         mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
5905                                 getConnectingSsidInternal(), bssid,
5906                                 WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION,
5907                                 isConnected());
5908                     }
5909                     WifiConfiguration config = getConnectedWifiConfigurationInternal();
5910                     if (config == null) {
5911                         config = getConnectingWifiConfigurationInternal();
5912                     }
5913                     clearNetworkCachedDataIfNeeded(config, eventInfo.reasonCode);
5914                     try {
5915                         logEventIfManagedNetwork(config,
5916                                 SupplicantStaIfaceHal.SUPPLICANT_EVENT_DISCONNECTED,
5917                                 MacAddress.fromString(eventInfo.bssid),
5918                                 "reason=" + StaIfaceReasonCode.toString(eventInfo.reasonCode));
5919                     } catch (IllegalArgumentException e) {
5920                         Log.e(TAG, "Invalid bssid received for disconnection event");
5921                     }
5922                     boolean newConnectionInProgress = isNewConnectionInProgress(eventInfo.ssid);
5923                     if (!newConnectionInProgress) {
5924                         int level2FailureReason = eventInfo.locallyGenerated
5925                                 ? WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN :
5926                                 WifiMetricsProto.ConnectionEvent.DISCONNECTION_NON_LOCAL;
5927                         if (!eventInfo.locallyGenerated) {
5928                             mWifiScoreCard.noteNonlocalDisconnect(
5929                                     mInterfaceName, eventInfo.reasonCode);
5930                         }
5931                         reportConnectionAttemptEnd(
5932                                 WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
5933                                 WifiMetricsProto.ConnectionEvent.HLF_NONE, level2FailureReason,
5934                                 eventInfo.reasonCode);
5935                     }
5936                     handleNetworkDisconnect(newConnectionInProgress, eventInfo.reasonCode);
5937                     if (!newConnectionInProgress) {
5938                         transitionTo(mDisconnectedState);
5939                     }
5940                     mTermsAndConditionsUrl = null;
5941                     break;
5942                 }
5943                 case WifiMonitor.TARGET_BSSID_EVENT: {
5944                     // Trying to associate to this BSSID
5945                     if (message.obj != null) {
5946                         mTargetBssid = (String) message.obj;
5947                     }
5948                     break;
5949                 }
5950                 case WifiMonitor.AUXILIARY_SUPPLICANT_EVENT: {
5951                     SupplicantEventInfo eventInfo = (SupplicantEventInfo) message.obj;
5952                     logEventIfManagedNetwork(getConnectingWifiConfigurationInternal(),
5953                             eventInfo.eventCode, eventInfo.bssid,
5954                             eventInfo.reasonString);
5955                     if (!TextUtils.isEmpty(eventInfo.reasonString)
5956                             && eventInfo.reasonString.contains(
5957                                     X509_CERTIFICATE_EXPIRED_ERROR_STRING)) {
5958                         mCurrentConnectionReportedCertificateExpired = true;
5959                         Log.e(getTag(), "Current connection attempt detected expired certificate");
5960                     }
5961                     break;
5962                 }
5963                 case CMD_DISCONNECT: {
5964                     mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5965                             message.arg1);
5966                     mWifiNative.disconnect(mInterfaceName);
5967                     break;
5968                 }
5969                 case CMD_PRE_DHCP_ACTION:
5970                 case CMD_PRE_DHCP_ACTION_COMPLETE:
5971                 case CMD_POST_DHCP_ACTION:
5972                 case CMD_IPV4_PROVISIONING_SUCCESS:
5973                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
5974                 case CMD_IPV4_PROVISIONING_FAILURE: {
5975                     handleStatus = handleL3MessagesWhenNotConnected(message);
5976                     break;
5977                 }
5978                 case WifiMonitor.TRANSITION_DISABLE_INDICATION: {
5979                     log("Received TRANSITION_DISABLE_INDICATION: networkId=" + message.arg1
5980                             + ", indication=" + message.arg2 + ", bssid=" + mLastBssid);
5981                     if (isValidTransitionDisableIndicationSource(mLastBssid, message.arg2)) {
5982                         mWifiConfigManager.updateNetworkTransitionDisable(message.arg1,
5983                                 message.arg2);
5984                     } else {
5985                         Log.w(getTag(), "Drop TRANSITION_DISABLE_INDICATION event"
5986                                 + " from an invalid source.");
5987                     }
5988                     break;
5989                 }
5990                 case WifiMonitor.QOS_POLICY_RESET_EVENT: {
5991                     if (SdkLevel.isAtLeastT() && mNetworkAgent != null
5992                             && mWifiNative.isQosPolicyFeatureEnabled()) {
5993                         mNetworkAgent.sendRemoveAllDscpPolicies();
5994                     }
5995                     break;
5996                 }
5997                 case WifiMonitor.QOS_POLICY_REQUEST_EVENT: {
5998                     if (SdkLevel.isAtLeastT() && mWifiNative.isQosPolicyFeatureEnabled()) {
5999                         mQosPolicyRequestHandler.queueQosPolicyRequest(
6000                                 message.arg1, (List<QosPolicyRequest>) message.obj);
6001                     }
6002                     break;
6003                 }
6004                 case CMD_REJECT_EAP_INSECURE_CONNECTION: {
6005                     log("Received CMD_REJECT_EAP_INSECURE_CONNECTION event");
6006                     boolean disconnectRequired = message.arg2 == 1;
6007 
6008                     // TOFU connections are not established until the user approves the certificate.
6009                     // If TOFU is not supported and the network is already connected, this will
6010                     // disconnect the network.
6011                     if (disconnectRequired) {
6012                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_UNTRUSTED;
6013                         sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_UNTRUSTED);
6014                     }
6015                     break;
6016                 }
6017                 default: {
6018                     handleStatus = NOT_HANDLED;
6019                     break;
6020                 }
6021             }
6022             if (handleStatus == HANDLED) {
6023                 logStateAndMessage(message, this);
6024             }
6025             return handleStatus;
6026         }
6027 
isValidTransitionDisableIndicationSource(String bssid, @WifiMonitor.TransitionDisableIndication int indicationBit)6028         private boolean isValidTransitionDisableIndicationSource(String bssid,
6029                 @WifiMonitor.TransitionDisableIndication int indicationBit) {
6030             ScanResult result = mScanRequestProxy.getScanResult(mLastBssid);
6031             if (null == result) return false;
6032 
6033             // SAE TDI should only come from a PSK/SAE BSS or a SAE BSS.
6034             if (0 != (indicationBit & WifiMonitor.TDI_USE_WPA3_PERSONAL)) {
6035                 return ScanResultUtil.isScanResultForSaeNetwork(result)
6036                         || ScanResultUtil.isScanResultForPskSaeTransitionNetwork(result);
6037             }
6038             // SAE_PK TDI should only come from a SAE BSS.
6039             if (0 != (indicationBit & WifiMonitor.TDI_USE_SAE_PK)) {
6040                 return ScanResultUtil.isScanResultForSaeNetwork(result);
6041             }
6042             // WPA3 Enterprise TDI should only come from a WPA2/WPA3 Enterprise
6043             // BSS or a WPA3 Enterprise BSS.
6044             if (0 != (indicationBit & WifiMonitor.TDI_USE_WPA3_ENTERPRISE)) {
6045                 return ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(result)
6046                         || ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(result);
6047             }
6048             // OWE TDI should only come from an OPEN/OWE BSS or an OWE BSS.
6049             if (0 != (indicationBit & WifiMonitor.TDI_USE_ENHANCED_OPEN)) {
6050                 return ScanResultUtil.isScanResultForOweNetwork(result)
6051                         || ScanResultUtil.isScanResultForOweTransitionNetwork(result);
6052             }
6053             return false;
6054         }
6055     }
6056 
6057     class L2ConnectingState extends RunnerState {
L2ConnectingState(int threshold)6058         L2ConnectingState(int threshold) {
6059             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
6060         }
6061 
6062         @Override
enterImpl()6063         public void enterImpl() {
6064             if (mVerboseLoggingEnabled) Log.v(getTag(), "Entering L2ConnectingState");
6065             // Make sure we connect: we enter this state prior to connecting to a new
6066             // network. In some cases supplicant ignores the connect requests (it might not
6067             // find the target SSID in its cache), Therefore we end up stuck that state, hence the
6068             // need for the watchdog.
6069             mConnectingWatchdogCount++;
6070             logd("Start Connecting Watchdog " + mConnectingWatchdogCount);
6071             sendMessageDelayed(obtainMessage(CMD_CONNECTING_WATCHDOG_TIMER,
6072                     mConnectingWatchdogCount, 0), CONNECTING_WATCHDOG_TIMEOUT_MS);
6073         }
6074 
6075         @Override
exitImpl()6076         public void exitImpl() {
6077             if (mVerboseLoggingEnabled) Log.v(getTag(), "Exiting L2ConnectingState");
6078             // Cancel any pending CMD_CONNECTING_WATCHDOG_TIMER since this is only valid in
6079             // L2ConnectingState anyway.
6080             removeMessages(CMD_CONNECTING_WATCHDOG_TIMER);
6081         }
6082 
6083         @Override
getMessageLogRec(int what)6084         public String getMessageLogRec(int what) {
6085             return ClientModeImpl.class.getSimpleName() + "."
6086                     + L2ConnectingState.class.getSimpleName() + "." + getWhatToString(what);
6087         }
6088 
6089         @Override
processMessageImpl(Message message)6090         public boolean processMessageImpl(Message message) {
6091             boolean handleStatus = HANDLED;
6092             switch (message.what) {
6093                 case WifiMonitor.NETWORK_NOT_FOUND_EVENT:
6094                     mNetworkNotFoundEventCount++;
6095                     String networkName = (String) message.obj;
6096                     if (networkName != null && !networkName.equals(getConnectingSsidInternal())) {
6097                         loge("Network not found event received, network: " + networkName
6098                                 + " which is not the target network: "
6099                                 + getConnectingSsidInternal());
6100                         break;
6101                     }
6102                     Log.d(getTag(), "Network not found event received: network: " + networkName);
6103                     if (mNetworkNotFoundEventCount
6104                             >= mWifiGlobals.getNetworkNotFoundEventThreshold()
6105                             && mTargetWifiConfiguration != null
6106                             && mTargetWifiConfiguration.SSID != null
6107                             && mTargetWifiConfiguration.SSID.equals(networkName)) {
6108                         stopIpClient();
6109                         mWifiConfigManager.updateNetworkSelectionStatus(
6110                                 mTargetWifiConfiguration.networkId,
6111                                 WifiConfiguration.NetworkSelectionStatus
6112                                         .DISABLED_NETWORK_NOT_FOUND);
6113                         if (SdkLevel.isAtLeastS()) {
6114                             mWifiConfigManager.setRecentFailureAssociationStatus(
6115                                     mTargetWifiConfiguration.networkId,
6116                                     WifiConfiguration.RECENT_FAILURE_NETWORK_NOT_FOUND);
6117                         }
6118                         reportConnectionAttemptEnd(
6119                                 WifiMetrics.ConnectionEvent.FAILURE_NETWORK_NOT_FOUND,
6120                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
6121                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
6122                         handleNetworkDisconnect(false,
6123                                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__UNSPECIFIED);
6124                         // TODO(b/302728081): remove the code once the issue is resolved.
6125                         if (mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()
6126                                 && mTargetWifiConfiguration.enterpriseConfig != null
6127                                 && mTargetWifiConfiguration.enterpriseConfig
6128                                         .isAuthenticationSimBased()
6129                                 && mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(
6130                                         mTargetWifiConfiguration.carrierId)) {
6131                             String bugTitle = "Wi-Fi BugReport: suspicious NETWORK_NOT_FOUND";
6132                             String bugDetail = "Detect abnormal NETWORK_NOT_FOUND error";
6133                             mWifiDiagnostics.takeBugReport(bugTitle, bugDetail);
6134                         }
6135                         transitionTo(mDisconnectedState); // End of connection attempt.
6136                     }
6137                     break;
6138                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: {
6139                     AssocRejectEventInfo assocRejectEventInfo = (AssocRejectEventInfo) message.obj;
6140                     log("L2ConnectingState: Association rejection " + assocRejectEventInfo);
6141                     if (!assocRejectEventInfo.ssid.equals(getConnectingSsidInternal())) {
6142                         loge("Association rejection event received on not target network");
6143                         break;
6144                     }
6145                     stopIpClient();
6146                     mWifiDiagnostics.triggerBugReportDataCapture(
6147                             WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
6148                     String bssid = assocRejectEventInfo.bssid;
6149                     boolean timedOut = assocRejectEventInfo.timedOut;
6150                     int statusCode = assocRejectEventInfo.statusCode;
6151                     if (!isValidBssid(bssid)) {
6152                         // If BSSID is null, use the target roam BSSID
6153                         bssid = mTargetBssid;
6154                     } else if (SUPPLICANT_BSSID_ANY.equals(mTargetBssid)) {
6155                         // This is needed by WifiBlocklistMonitor to block continuously
6156                         // failing BSSIDs. Need to set here because mTargetBssid is currently
6157                         // not being set until association success.
6158                         mTargetBssid = bssid;
6159                     }
6160                     if (!isSecondaryInternet()) {
6161                         mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
6162                                 WifiConfiguration.NetworkSelectionStatus
6163                                         .DISABLED_ASSOCIATION_REJECTION);
6164                     }
6165                     setAssociationRejectionStatusInConfig(mTargetNetworkId, assocRejectEventInfo);
6166                     int level2FailureReason =
6167                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN;
6168                     if (statusCode == StaIfaceStatusCode.AP_UNABLE_TO_HANDLE_NEW_STA
6169                             || statusCode == StaIfaceStatusCode.ASSOC_REJECTED_TEMPORARILY
6170                             || statusCode == StaIfaceStatusCode.DENIED_INSUFFICIENT_BANDWIDTH) {
6171                         level2FailureReason = WifiMetricsProto.ConnectionEvent
6172                                 .ASSOCIATION_REJECTION_AP_UNABLE_TO_HANDLE_NEW_STA;
6173                     }
6174 
6175                     // If rejection occurred while Metrics is tracking a ConnectionEvent, end it.
6176                     reportConnectionAttemptEnd(
6177                             timedOut
6178                                     ? WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT
6179                                     : WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
6180                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
6181                             level2FailureReason, timedOut ? 0 : statusCode);
6182 
6183                     if (level2FailureReason != WifiMetricsProto.ConnectionEvent
6184                             .ASSOCIATION_REJECTION_AP_UNABLE_TO_HANDLE_NEW_STA
6185                             && !isSecondaryInternet()) {
6186                         mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
6187                                 getConnectingSsidInternal(), bssid,
6188                                 WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION,
6189                                 isConnected());
6190                     }
6191                     handleNetworkDisconnect(false,
6192                             WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__UNSPECIFIED);
6193                     transitionTo(mDisconnectedState); // End of connection attempt.
6194                     break;
6195                 }
6196                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: {
6197                     AuthenticationFailureEventInfo authenticationFailureEventInfo =
6198                             (AuthenticationFailureEventInfo) message.obj;
6199                     if (!TextUtils.equals(authenticationFailureEventInfo.ssid,
6200                             getConnectingSsidInternal())) {
6201                         logw("Authentication failure event received on not target network");
6202                         break;
6203                     }
6204                     stopIpClient();
6205                     mWifiDiagnostics.triggerBugReportDataCapture(
6206                             WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
6207                     int disableReason = WifiConfiguration.NetworkSelectionStatus
6208                             .DISABLED_AUTHENTICATION_FAILURE;
6209                     int reasonCode = authenticationFailureEventInfo.reasonCode;
6210                     int errorCode = authenticationFailureEventInfo.errorCode;
6211                     log("L2ConnectingState: Authentication failure "
6212                             + " reason=" + reasonCode + " error=" + errorCode);
6213                     WifiConfiguration targetedNetwork =
6214                             mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
6215                     // Check if this is a permanent wrong password failure.
6216                     if (isPermanentWrongPasswordFailure(mTargetNetworkId, reasonCode)) {
6217                         disableReason = WifiConfiguration.NetworkSelectionStatus
6218                                 .DISABLED_BY_WRONG_PASSWORD;
6219                         // For primary role, send error notification except for local only network,
6220                         // for secondary role, send only for secondary internet.
6221                         final boolean isForLocalOnly = isRequestedForLocalOnly(
6222                                 targetedNetwork, mTargetBssid) || isLocalOnly();
6223                         final boolean needNotifyError = isPrimary() ? !isForLocalOnly
6224                                 : isSecondaryInternet();
6225                         if (targetedNetwork != null && needNotifyError) {
6226                             mWrongPasswordNotifier.onWrongPasswordError(targetedNetwork);
6227                         }
6228                     } else if (reasonCode == WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
6229                         logEventIfManagedNetwork(targetedNetwork,
6230                                 SupplicantStaIfaceHal.SUPPLICANT_EVENT_EAP_FAILURE,
6231                                 authenticationFailureEventInfo.bssid, "error=" + errorCode);
6232                         if (targetedNetwork != null && targetedNetwork.enterpriseConfig != null
6233                                 && targetedNetwork.enterpriseConfig.isAuthenticationSimBased()) {
6234                             // only show EAP failure notification if primary
6235                             WifiBlocklistMonitor.CarrierSpecificEapFailureConfig eapFailureConfig =
6236                                     mEapFailureNotifier.onEapFailure(errorCode, targetedNetwork,
6237                                             isPrimary());
6238                             if (eapFailureConfig != null) {
6239                                 disableReason = WifiConfiguration.NetworkSelectionStatus
6240                                     .DISABLED_AUTHENTICATION_PRIVATE_EAP_ERROR;
6241                                 mWifiBlocklistMonitor.loadCarrierConfigsForDisableReasonInfos(
6242                                         eapFailureConfig);
6243                             }
6244                         }
6245                         handleEapAuthFailure(mTargetNetworkId, errorCode);
6246                         if (errorCode == WifiNative.EAP_SIM_NOT_SUBSCRIBED) {
6247                             disableReason = WifiConfiguration.NetworkSelectionStatus
6248                                     .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION;
6249                         }
6250                         if (mCurrentConnectionReportedCertificateExpired && errorCode <= 0) {
6251                             errorCode = EAP_FAILURE_CODE_CERTIFICATE_EXPIRED;
6252                         }
6253                     }
6254                     mWifiConfigManager.updateNetworkSelectionStatus(
6255                             mTargetNetworkId, disableReason);
6256                     mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);
6257 
6258                     //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
6259                     int level2FailureReason;
6260                     switch (reasonCode) {
6261                         case WifiManager.ERROR_AUTH_FAILURE_NONE:
6262                             level2FailureReason =
6263                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE;
6264                             break;
6265                         case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
6266                             level2FailureReason =
6267                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_TIMEOUT;
6268                             break;
6269                         case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
6270                             level2FailureReason =
6271                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD;
6272                             break;
6273                         case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
6274                             level2FailureReason =
6275                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE;
6276                             break;
6277                         default:
6278                             level2FailureReason =
6279                                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN;
6280                             break;
6281                     }
6282                     reportConnectionAttemptEnd(
6283                             WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
6284                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
6285                             level2FailureReason, errorCode);
6286                     if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD && reasonCode
6287                             != WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
6288                         mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
6289                                 getConnectingSsidInternal(),
6290                                 (mLastBssid == null) ? mTargetBssid : mLastBssid,
6291                                 WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION,
6292                                 isConnected());
6293                     }
6294                     handleNetworkDisconnect(false,
6295                             WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__UNSPECIFIED);
6296                     transitionTo(mDisconnectedState); // End of connection attempt.
6297                     break;
6298                 }
6299                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: {
6300                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6301                     if (SupplicantState.isConnecting(stateChangeResult.state)) {
6302                         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(
6303                                 stateChangeResult.networkId);
6304                         // Update Passpoint information before setNetworkDetailedState as
6305                         // WifiTracker monitors NETWORK_STATE_CHANGED_ACTION to update UI.
6306                         mWifiInfo.setFQDN(null);
6307                         mWifiInfo.setPasspointUniqueId(null);
6308                         mWifiInfo.setOsuAp(false);
6309                         mWifiInfo.setProviderFriendlyName(null);
6310                         if (config != null && (config.isPasspoint() || config.osu)) {
6311                             if (config.isPasspoint()) {
6312                                 mWifiInfo.setFQDN(config.FQDN);
6313                                 mWifiInfo.setPasspointUniqueId(config.getPasspointUniqueId());
6314                             } else {
6315                                 mWifiInfo.setOsuAp(true);
6316                             }
6317                             mWifiInfo.setProviderFriendlyName(config.providerFriendlyName);
6318                             mWifiInfo.setNetworkKey(
6319                                     config.getNetworkKeyFromSecurityType(
6320                                             mWifiInfo.getCurrentSecurityType()));
6321                         }
6322                         updateCurrentConnectionInfo();
6323                     }
6324                     sendNetworkChangeBroadcast(
6325                             WifiInfo.getDetailedStateOf(stateChangeResult.state));
6326                     // Let the parent state handle the rest of the state changed.
6327                     handleStatus = NOT_HANDLED;
6328                     break;
6329                 }
6330                 case WifiMonitor.SUP_REQUEST_IDENTITY: {
6331                     int netId = message.arg2;
6332                     boolean identitySent = false;
6333                     // For SIM & AKA/AKA' EAP method Only, get identity from ICC
6334                     if (mTargetWifiConfiguration != null
6335                             && mTargetWifiConfiguration.networkId == netId
6336                             && mTargetWifiConfiguration.enterpriseConfig != null
6337                             && mTargetWifiConfiguration.enterpriseConfig
6338                             .isAuthenticationSimBased()) {
6339                         // Pair<identity, encrypted identity>
6340                         Pair<String, String> identityPair = mWifiCarrierInfoManager
6341                                 .getSimIdentity(mTargetWifiConfiguration);
6342                         if (identityPair != null && identityPair.first != null) {
6343                             Log.i(getTag(), "SUP_REQUEST_IDENTITY: identityPair=["
6344                                     + ((identityPair.first.length() >= 7)
6345                                     ? identityPair.first.substring(0, 7 /* Prefix+PLMN ID */)
6346                                     + "****"
6347                                     : identityPair.first) + ", "
6348                                     + (!TextUtils.isEmpty(identityPair.second) ? identityPair.second
6349                                     : "<NONE>") + "]");
6350                             mWifiNative.simIdentityResponse(mInterfaceName, identityPair.first,
6351                                     identityPair.second);
6352                             identitySent = true;
6353                         } else {
6354                             Log.e(getTag(), "Unable to retrieve identity from Telephony");
6355                         }
6356                     }
6357 
6358                     if (!identitySent) {
6359                         // Supplicant lacks credentials to connect to that network, hence block list
6360                         String ssid = (String) message.obj;
6361                         if (mTargetWifiConfiguration != null && ssid != null
6362                                 && mTargetWifiConfiguration.SSID != null
6363                                 && mTargetWifiConfiguration.SSID.equals("\"" + ssid + "\"")) {
6364                             mWifiConfigManager.updateNetworkSelectionStatus(
6365                                     mTargetWifiConfiguration.networkId,
6366                                     WifiConfiguration.NetworkSelectionStatus
6367                                             .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
6368                         }
6369                         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6370                                 StaEvent.DISCONNECT_GENERIC);
6371                         mWifiNative.disconnect(mInterfaceName);
6372                     }
6373                     break;
6374                 }
6375                 case CMD_CONNECTING_WATCHDOG_TIMER: {
6376                     if (mConnectingWatchdogCount == message.arg1) {
6377                         if (mVerboseLoggingEnabled) log("Connecting watchdog! -> disconnect");
6378                         reportConnectionAttemptEnd(
6379                                 WifiMetrics.ConnectionEvent.FAILURE_NO_RESPONSE,
6380                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
6381                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
6382                         handleNetworkDisconnect(false,
6383                                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__CONNECTING_WATCHDOG_TIMER);
6384                         transitionTo(mDisconnectedState);
6385                     }
6386                     break;
6387                 }
6388                 case WifiMonitor.NETWORK_CONNECTION_EVENT: {
6389                     NetworkConnectionEventInfo connectionInfo =
6390                             (NetworkConnectionEventInfo) message.obj;
6391                     String quotedOrHexConnectingSsid = getConnectingSsidInternal();
6392                     String quotedOrHexConnectedSsid = connectionInfo.wifiSsid.toString();
6393                     if (quotedOrHexConnectingSsid != null
6394                             && !quotedOrHexConnectingSsid.equals(quotedOrHexConnectedSsid)) {
6395                         // possibly a NETWORK_CONNECTION_EVENT for a successful roam on the previous
6396                         // network while connecting to a new network, ignore it.
6397                         Log.d(TAG, "Connecting to ssid=" + quotedOrHexConnectingSsid + ", but got "
6398                                 + "NETWORK_CONNECTION_EVENT for ssid=" + quotedOrHexConnectedSsid
6399                                 + ", ignoring");
6400                         break;
6401                     }
6402                     handleStatus = NOT_HANDLED;
6403                     break;
6404                 }
6405                 case WifiMonitor.TOFU_CERTIFICATE_EVENT: {
6406                     if (null == mTargetWifiConfiguration) break;
6407                     int networkId = message.arg1;
6408                     final int certificateDepth = message.arg2;
6409                     final CertificateEventInfo eventInfo = (CertificateEventInfo) message.obj;
6410                     if (!mInsecureEapNetworkHandler.addPendingCertificate(
6411                             networkId, certificateDepth, eventInfo)) {
6412                         Log.d(TAG, "Cannot set pending cert.");
6413                     }
6414                     // Launch user approval upon receiving the server certificate and disconnect
6415                     if (certificateDepth == 0 && !mLeafCertSent && mInsecureEapNetworkHandler
6416                             .startUserApprovalIfNecessary(mIsUserSelected)) {
6417                         // In the TOFU flow, the user approval dialog is now displayed and the
6418                         // network remains disconnected and disabled until it is approved.
6419                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_UNTRUSTED;
6420                         sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_UNTRUSTED);
6421                         mLeafCertSent = true;
6422                     }
6423                     break;
6424                 }
6425                 default: {
6426                     handleStatus = NOT_HANDLED;
6427                     break;
6428                 }
6429             }
6430             if (handleStatus == HANDLED) {
6431                 logStateAndMessage(message, this);
6432             }
6433             return handleStatus;
6434         }
6435     }
6436 
6437     class L2ConnectedState extends RunnerState {
L2ConnectedState(int threshold)6438         L2ConnectedState(int threshold) {
6439             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
6440         }
6441 
6442         @Override
enterImpl()6443         public void enterImpl() {
6444             final WifiConfiguration config = getConnectedWifiConfigurationInternal();
6445             if (config == null) {
6446                 logw("Connected to a network that's already been removed " + mLastNetworkId
6447                         + ", disconnecting...");
6448                 sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_UNKNOWN_NETWORK);
6449                 return;
6450             }
6451 
6452             mRssiPollToken++;
6453             if (mEnableRssiPolling) {
6454                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
6455             } else {
6456                 updateLinkLayerStatsRssiAndScoreReport();
6457             }
6458             sendNetworkChangeBroadcast(DetailedState.CONNECTING);
6459             // If this network was explicitly selected by the user, evaluate whether to inform
6460             // ConnectivityService of that fact so the system can treat it appropriately.
6461             final NetworkAgentConfig naConfig = getNetworkAgentConfigInternal(config);
6462             final NetworkCapabilities nc = getCapabilities(
6463                     getConnectedWifiConfigurationInternal(), getConnectedBssidInternal());
6464             // This should never happen.
6465             if (mNetworkAgent != null) {
6466                 Log.wtf(getTag(), "mNetworkAgent is not null: " + mNetworkAgent);
6467                 mNetworkAgent.unregister();
6468             }
6469             mNetworkAgent = mWifiInjector.makeWifiNetworkAgent(nc, mLinkProperties, naConfig,
6470                     mNetworkFactory.getProvider(), new WifiNetworkAgentCallback());
6471             mWifiScoreReport.setNetworkAgent(mNetworkAgent);
6472             if (SdkLevel.isAtLeastT()) {
6473                 mQosPolicyRequestHandler.setNetworkAgent(mNetworkAgent);
6474             }
6475 
6476             // We must clear the config BSSID, as the wifi chipset may decide to roam
6477             // from this point on and having the BSSID specified in the network block would
6478             // cause the roam to faile and the device to disconnect
6479             clearTargetBssid("L2ConnectedState");
6480             mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
6481             mWifiScoreCard.noteNetworkAgentCreated(mWifiInfo,
6482                     mNetworkAgent.getNetwork().getNetId());
6483             mWifiBlocklistMonitor.handleBssidConnectionSuccess(mLastBssid, mWifiInfo.getSSID());
6484             // too many places to record connection failure with too many failure reasons.
6485             // So only record success here.
6486             mWifiMetrics.noteFirstL2ConnectionAfterBoot(true);
6487             mCmiMonitor.onL2Connected(mClientModeManager);
6488             mIsLinkedNetworkRoaming = false;
6489         }
6490 
6491         @Override
exitImpl()6492         public void exitImpl() {
6493             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectableState
6494             // Bug: 15347363
6495             // For paranoia's sake, call handleNetworkDisconnect
6496             // only if BSSID is null or last networkId
6497             // is not invalid.
6498             if (mVerboseLoggingEnabled) {
6499                 StringBuilder sb = new StringBuilder();
6500                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
6501                 if (mLastBssid != null) {
6502                     sb.append(" ").append(mLastBssid);
6503                 }
6504             }
6505             mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
6506             mWifiStateTracker.updateState(mInterfaceName, WifiStateTracker.DISCONNECTED);
6507             // Inform WifiLockManager
6508             mWifiLockManager.updateWifiClientConnected(mClientModeManager, false);
6509             mLastConnectionCapabilities = null;
6510         }
6511 
6512         @Override
getMessageLogRec(int what)6513         public String getMessageLogRec(int what) {
6514             return ClientModeImpl.class.getSimpleName() + "."
6515                     + L2ConnectedState.class.getSimpleName() + "." + getWhatToString(what);
6516         }
6517 
6518         @Override
processMessageImpl(Message message)6519         public boolean processMessageImpl(Message message) {
6520             boolean handleStatus = HANDLED;
6521 
6522             switch (message.what) {
6523                 case CMD_PRE_DHCP_ACTION: {
6524                     if (!isFromCurrentIpClientCallbacks(message)) break;
6525                     handlePreDhcpSetup();
6526                     break;
6527                 }
6528                 case CMD_PRE_DHCP_ACTION_COMPLETE: {
6529                     if (mIpClient != null) {
6530                         mIpClient.completedPreDhcpAction();
6531                     }
6532                     break;
6533                 }
6534                 case CMD_POST_DHCP_ACTION: {
6535                     if (!isFromCurrentIpClientCallbacks(message)) break;
6536                     handlePostDhcpSetup();
6537                     // We advance to mL3ConnectedState because IpClient will also send a
6538                     // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
6539                     // which calls updateLinkProperties, which then sends
6540                     // CMD_IP_CONFIGURATION_SUCCESSFUL.
6541                     break;
6542                 }
6543                 case CMD_IPV4_PROVISIONING_SUCCESS: {
6544                     if (!isFromCurrentIpClientCallbacks(message)) break;
6545                     handleIPv4Success((DhcpResultsParcelable) message.obj);
6546                     sendNetworkChangeBroadcastWithCurrentState();
6547                     break;
6548                 }
6549                 case CMD_IPV4_PROVISIONING_FAILURE: {
6550                     if (!isFromCurrentIpClientCallbacks(message)) break;
6551                     handleIPv4Failure();
6552                     mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
6553                             getConnectingSsidInternal(),
6554                             (mLastBssid == null) ? mTargetBssid : mLastBssid,
6555                             WifiLastResortWatchdog.FAILURE_CODE_DHCP,
6556                             isConnected());
6557                     break;
6558                 }
6559                 case CMD_IP_CONFIGURATION_SUCCESSFUL: {
6560                     if (!isFromCurrentIpClientCallbacks(message)) break;
6561                     if (getConnectedWifiConfigurationInternal() == null || mNetworkAgent == null) {
6562                         // The current config may have been removed while we were connecting,
6563                         // trigger a disconnect to clear up state.
6564                         reportConnectionAttemptEnd(
6565                                 WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6566                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
6567                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
6568                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_REMOVED;
6569                         mWifiNative.disconnect(mInterfaceName);
6570                     } else {
6571                         handleSuccessfulIpConfiguration();
6572                         transitionTo(mL3ConnectedState);
6573                     }
6574                     break;
6575                 }
6576                 case CMD_IP_CONFIGURATION_LOST: {
6577                     if (!isFromCurrentIpClientCallbacks(message)) break;
6578                     // Get Link layer stats so that we get fresh tx packet counters.
6579                     getWifiLinkLayerStats();
6580                     handleIpConfigurationLost();
6581                     reportConnectionAttemptEnd(
6582                             WifiMetrics.ConnectionEvent.FAILURE_DHCP,
6583                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
6584                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
6585                     mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
6586                             getConnectingSsidInternal(),
6587                             (mLastBssid == null) ? mTargetBssid : mLastBssid,
6588                             WifiLastResortWatchdog.FAILURE_CODE_DHCP,
6589                             isConnected());
6590                     handleNetworkDisconnect(false,
6591                             WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__UNSPECIFIED);
6592                     transitionTo(mDisconnectedState); // End of connection attempt.
6593                     break;
6594                 }
6595                 case CMD_IP_REACHABILITY_LOST: {
6596                     if (!isFromCurrentIpClientCallbacks(message)) break;
6597                     if (mVerboseLoggingEnabled && message.obj != null) log((String) message.obj);
6598                     mWifiDiagnostics.triggerBugReportDataCapture(
6599                             WifiDiagnostics.REPORT_REASON_REACHABILITY_LOST);
6600                     mWifiMetrics.logWifiIsUnusableEvent(mInterfaceName,
6601                             WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST);
6602                     mWifiMetrics.addToWifiUsabilityStatsList(mInterfaceName,
6603                             WifiUsabilityStats.LABEL_BAD,
6604                             WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST, -1);
6605                     if (mWifiGlobals.getIpReachabilityDisconnectEnabled()) {
6606                         handleIpReachabilityLost(-1);
6607                     } else {
6608                         logd("CMD_IP_REACHABILITY_LOST but disconnect disabled -- ignore");
6609                     }
6610                     break;
6611                 }
6612                 case CMD_IP_REACHABILITY_FAILURE: {
6613                     if (!isFromCurrentIpClientCallbacks(message)) break;
6614                     mWifiDiagnostics.triggerBugReportDataCapture(
6615                             WifiDiagnostics.REPORT_REASON_REACHABILITY_FAILURE);
6616                     handleIpReachabilityFailure((ReachabilityLossInfoParcelable) message.obj);
6617                     break;
6618                 }
6619                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: {
6620                     if (mWifiP2pConnection.shouldTemporarilyDisconnectWifi()) {
6621                         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6622                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
6623                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_P2P_REQUESTED_DISCONNECT;
6624                         mWifiNative.disconnect(mInterfaceName);
6625                     }
6626                     break;
6627                 }
6628                 case WifiMonitor.NETWORK_CONNECTION_EVENT: {
6629                     NetworkConnectionEventInfo connectionInfo =
6630                             (NetworkConnectionEventInfo) message.obj;
6631                     mLastNetworkId = connectionInfo.networkId;
6632                     mWifiMetrics.onRoamComplete();
6633                     handleNetworkConnectionEventInfo(
6634                             getConnectedWifiConfigurationInternal(), connectionInfo);
6635                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
6636                     updateLayer2Information();
6637                     updateCurrentConnectionInfo();
6638                     if (!Objects.equals(mLastBssid, connectionInfo.bssid)) {
6639                         mLastBssid = connectionInfo.bssid;
6640                         sendNetworkChangeBroadcastWithCurrentState();
6641                     }
6642                     if (mIsLinkedNetworkRoaming) {
6643                         mIsLinkedNetworkRoaming = false;
6644                         mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
6645                         mTargetWifiConfiguration = null;
6646                         clearTargetBssid("AllowlistRoamingCompleted");
6647                         sendNetworkChangeBroadcast(DetailedState.CONNECTED);
6648                     }
6649                     checkIfNeedDisconnectSecondaryWifi();
6650                     if (mApplicationQosPolicyRequestHandler.isFeatureEnabled()) {
6651                         mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface(
6652                                 mInterfaceName, mostRecentConnectionSupports11ax());
6653                     }
6654                     break;
6655                 }
6656                 case WifiMonitor.BSS_FREQUENCY_CHANGED_EVENT: {
6657                     int newFrequency = message.arg1;
6658                     if (newFrequency > 0) {
6659                         boolean isNeedUpdate = false;
6660                         if (isMlo()) {
6661                             if (updateAssociatedMloLinksFromLinksInfoWhenBssFreqChanged(
6662                                     newFrequency)) {
6663                                 isNeedUpdate = true;
6664                             }
6665                         } else if (mWifiInfo.getFrequency() != newFrequency) {
6666                             mWifiInfo.setFrequency(newFrequency);
6667                             isNeedUpdate = true;
6668                         }
6669                         if (isNeedUpdate) {
6670                             updateCurrentConnectionInfo();
6671                             updateCapabilities();
6672                         }
6673                     }
6674                     break;
6675                 }
6676                 case CMD_ONESHOT_RSSI_POLL: {
6677                     if (!mEnableRssiPolling) {
6678                         updateLinkLayerStatsRssiDataStallScoreReport();
6679                     }
6680                     break;
6681                 }
6682                 case CMD_RSSI_POLL: {
6683                     // TODO(b/179792830): getBSSID() shouldn't be null in L2ConnectedState,
6684                     //  add debug logs in the meantime. Remove once root cause identified.
6685                     if (mWifiInfo.getBSSID() == null) {
6686                         Log.wtf(getTag(), "WifiInfo.getBSSID() is null in L2ConnectedState!");
6687                         break;
6688                     }
6689                     if (message.arg1 == mRssiPollToken) {
6690                         updateLinkLayerStatsRssiDataStallScoreReport();
6691                         mWifiScoreCard.noteSignalPoll(mWifiInfo);
6692                         // Update the polling interval as needed before sending the delayed message
6693                         // so that the next polling can happen after the updated interval
6694                         if (isPrimary()) {
6695                             int curState = mWifiInjector.getActiveModeWarden()
6696                                     .getDeviceMobilityState();
6697                             mRssiMonitor.updatePollRssiInterval(curState);
6698                         }
6699                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
6700                                 mWifiGlobals.getPollRssiIntervalMillis());
6701                         if (isPrimary()) {
6702                             mWifiTrafficPoller.notifyOnDataActivity(
6703                                     mWifiInfo.txSuccess, mWifiInfo.rxSuccess);
6704                         }
6705                     } else {
6706                         // Polling has completed
6707                     }
6708                     break;
6709                 }
6710                 case CMD_ENABLE_RSSI_POLL: {
6711                     cleanWifiScore();
6712                     mEnableRssiPolling = (message.arg1 == 1);
6713                     mRssiPollToken++;
6714                     if (mEnableRssiPolling) {
6715                         // First poll
6716                         mLastSignalLevel = -1;
6717                         long txBytes = mFacade.getTotalTxBytes() - mFacade.getMobileTxBytes();
6718                         long rxBytes = mFacade.getTotalRxBytes() - mFacade.getMobileRxBytes();
6719                         updateLinkLayerStatsRssiSpeedFrequencyCapabilities(txBytes, rxBytes);
6720                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
6721                                 mWifiGlobals.getPollRssiIntervalMillis());
6722                     }
6723                     else {
6724                         mRssiMonitor.setShortPollRssiInterval();
6725                         removeMessages(CMD_RSSI_POLL);
6726                     }
6727                     break;
6728                 }
6729                 case WifiMonitor.ASSOCIATED_BSSID_EVENT: {
6730                     if ((String) message.obj == null) {
6731                         logw("Associated command w/o BSSID");
6732                         break;
6733                     }
6734                     mLastBssid = (String) message.obj;
6735                     if (checkAndHandleLinkedNetworkRoaming(mLastBssid)) {
6736                         Log.i(TAG, "Driver initiated allowlist SSID roaming");
6737                         break;
6738                     }
6739                     if (mLastBssid != null && (mWifiInfo.getBSSID() == null
6740                             || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
6741                         mWifiInfo.setBSSID(mLastBssid);
6742                         WifiConfiguration config = getConnectedWifiConfigurationInternal();
6743                         if (config != null) {
6744                             ScanDetailCache scanDetailCache = mWifiConfigManager
6745                                     .getScanDetailCacheForNetwork(config.networkId);
6746                             if (scanDetailCache != null) {
6747                                 ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
6748                                 if (scanResult != null) {
6749                                     mWifiInfo.setFrequency(scanResult.frequency);
6750                                     boolean isHidden = true;
6751                                     for (byte b : scanResult.getWifiSsid().getBytes()) {
6752                                         if (b != 0) {
6753                                             isHidden = false;
6754                                             break;
6755                                         }
6756                                     }
6757                                     mWifiInfo.setHiddenSSID(isHidden);
6758                                 }
6759                             }
6760                         }
6761                         sendNetworkChangeBroadcastWithCurrentState();
6762                         mMultiInternetManager.notifyBssidAssociatedEvent(mClientModeManager);
6763                         updateCurrentConnectionInfo();
6764                     }
6765                     break;
6766                 }
6767                 case CMD_RECONNECT: {
6768                     log(" Ignore CMD_RECONNECT request because wifi is already connected");
6769                     break;
6770                 }
6771                 case CMD_RESET_SIM_NETWORKS: {
6772                     if (message.arg1 != RESET_SIM_REASON_SIM_INSERTED
6773                             && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6774                         WifiConfiguration config =
6775                                 mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
6776                         if (config != null
6777                             && ((message.arg1 == RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED
6778                                 && config.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID)
6779                                 || (config.enterpriseConfig != null
6780                                 && config.enterpriseConfig.isAuthenticationSimBased()
6781                                 && !mWifiCarrierInfoManager.isSimReady(mLastSubId)))) {
6782                             mWifiMetrics.logStaEvent(mInterfaceName,
6783                                     StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6784                                     StaEvent.DISCONNECT_RESET_SIM_NETWORKS);
6785                             // remove local PMKSA cache in framework
6786                             mWifiNative.removeNetworkCachedData(mLastNetworkId);
6787                             // remove network so that supplicant's PMKSA cache is cleared
6788                             mWifiNative.removeAllNetworks(mInterfaceName);
6789                             if (isPrimary() && !mWifiCarrierInfoManager.isSimReady(mLastSubId)) {
6790                                 mSimRequiredNotifier.showSimRequiredNotification(
6791                                         config, mLastSimBasedConnectionCarrierName);
6792                             }
6793                         }
6794                     }
6795                     break;
6796                 }
6797                 case CMD_START_IP_PACKET_OFFLOAD: {
6798                     int slot = message.arg1;
6799                     int intervalSeconds = message.arg2;
6800                     KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
6801                     int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
6802                     if (mNetworkAgent != null) {
6803                         mNetworkAgent.sendSocketKeepaliveEvent(slot, result);
6804                     }
6805                     break;
6806                 }
6807                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
6808                     if (mIpClient != null) {
6809                         final int slot = message.arg1;
6810                         if (message.obj instanceof NattKeepalivePacketData) {
6811                             final NattKeepalivePacketData pkt =
6812                                     (NattKeepalivePacketData) message.obj;
6813                             mIpClient.addKeepalivePacketFilter(slot, pkt);
6814                         } else if (SdkLevel.isAtLeastS()) {
6815                             if (message.obj instanceof TcpKeepalivePacketData) {
6816                                 final TcpKeepalivePacketData pkt =
6817                                         (TcpKeepalivePacketData) message.obj;
6818                                 mIpClient.addKeepalivePacketFilter(slot, pkt);
6819                             }
6820                             // Otherwise unsupported keepalive data class: skip
6821                         } else {
6822                             // Before S, non-NattKeepalivePacketData KeepalivePacketData would be
6823                             // the not-yet-SystemApi android.net.TcpKeepalivePacketData.
6824                             // Attempt to parse TcpKeepalivePacketDataParcelable from the
6825                             // KeepalivePacketData superclass.
6826                             final TcpKeepalivePacketDataParcelable p =
6827                                     parseTcpKeepalivePacketData((KeepalivePacketData) message.obj);
6828                             if (p != null) {
6829                                 mIpClient.addKeepalivePacketFilter(slot, p);
6830                             }
6831                         }
6832                     }
6833                     break;
6834                 }
6835                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
6836                     if (mIpClient != null) {
6837                         mIpClient.removeKeepalivePacketFilter(message.arg1);
6838                     }
6839                     break;
6840                 }
6841                 case WifiMonitor.MLO_LINKS_INFO_CHANGED:
6842                     WifiMonitor.MloLinkInfoChangeReason reason =
6843                             (WifiMonitor.MloLinkInfoChangeReason) message.obj;
6844                     WifiNative.ConnectionMloLinksInfo newInfo =
6845                             mWifiNative.getConnectionMloLinksInfo(mInterfaceName);
6846                     if (reason == WifiMonitor.MloLinkInfoChangeReason.TID_TO_LINK_MAP) {
6847                         // Traffic stream mapping changed. Update link states.
6848                         updateMloLinkStates(newInfo);
6849                         // There is a change in link capabilities. Will trigger android.net
6850                         // .ConnectivityManager.NetworkCallback.onCapabilitiesChanged().
6851                         updateCapabilities();
6852                     } else if (reason
6853                             == WifiMonitor.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL) {
6854                         // Link is removed. Set removed link state to MLO_LINK_STATE_UNASSOCIATED.
6855                         // Also update block list mapping, as there is a change in affiliated
6856                         // BSSIDs.
6857                         clearMloLinkStates();
6858                         updateMloLinkStates(newInfo);
6859                         updateBlockListAffiliatedBssids();
6860                         // There is a change in link capabilities. Will trigger android.net
6861                         // .ConnectivityManager.NetworkCallback.onCapabilitiesChanged().
6862                         updateCapabilities();
6863                     } else {
6864                         logw("MLO_LINKS_INFO_CHANGED with UNKNOWN reason");
6865                     }
6866                     break;
6867                 default: {
6868                     handleStatus = NOT_HANDLED;
6869                     break;
6870                 }
6871             }
6872 
6873             if (handleStatus == HANDLED) {
6874                 logStateAndMessage(message, this);
6875             }
6876 
6877             return handleStatus;
6878         }
6879 
6880         /**
6881          * Fetches link stats, updates Wifi Data Stall, Score Card and Score Report.
6882          */
updateLinkLayerStatsRssiDataStallScoreReport()6883         private WifiLinkLayerStats updateLinkLayerStatsRssiDataStallScoreReport() {
6884             // Get Info and continue polling
6885             long txBytes;
6886             long rxBytes;
6887             if (SdkLevel.isAtLeastS()) {
6888                 txBytes = mFacade.getTxBytes(mInterfaceName);
6889                 rxBytes = mFacade.getRxBytes(mInterfaceName);
6890             } else {
6891                 txBytes = mFacade.getTotalTxBytes() - mFacade.getMobileTxBytes();
6892                 rxBytes = mFacade.getTotalRxBytes() - mFacade.getMobileRxBytes();
6893             }
6894             WifiLinkLayerStats stats = updateLinkLayerStatsRssiSpeedFrequencyCapabilities(txBytes,
6895                     rxBytes);
6896             mWifiMetrics.updateWifiUsabilityStatsEntries(mInterfaceName, mWifiInfo, stats);
6897             // checkDataStallAndThroughputSufficiency() should be called before
6898             // mWifiScoreReport.calculateAndReportScore() which needs the latest throughput
6899             int statusDataStall = mWifiDataStall.checkDataStallAndThroughputSufficiency(
6900                     mInterfaceName, mLastConnectionCapabilities, mLastLinkLayerStats, stats,
6901                     mWifiInfo, txBytes, rxBytes);
6902             if (mDataStallTriggerTimeMs == -1
6903                     && statusDataStall != WifiIsUnusableEvent.TYPE_UNKNOWN) {
6904                 mDataStallTriggerTimeMs = mClock.getElapsedSinceBootMillis();
6905                 mLastStatusDataStall = statusDataStall;
6906             }
6907             if (mDataStallTriggerTimeMs != -1) {
6908                 long elapsedTime =  mClock.getElapsedSinceBootMillis()
6909                         - mDataStallTriggerTimeMs;
6910                 if (elapsedTime >= DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS) {
6911                     mDataStallTriggerTimeMs = -1;
6912                     mWifiMetrics.addToWifiUsabilityStatsList(mInterfaceName,
6913                             WifiUsabilityStats.LABEL_BAD,
6914                             convertToUsabilityStatsTriggerType(mLastStatusDataStall),
6915                             -1);
6916                     mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
6917                 }
6918             }
6919             // Send the update score to network agent.
6920             mWifiScoreReport.calculateAndReportScore();
6921 
6922             if (mWifiScoreReport.shouldCheckIpLayer()) {
6923                 if (mIpClient != null) {
6924                     mIpClient.confirmConfiguration();
6925                 }
6926                 mWifiScoreReport.noteIpCheck();
6927             }
6928 
6929             mLastLinkLayerStats = stats;
6930             return stats;
6931         }
6932     }
6933 
6934     /**
6935      * Fetches link stats and updates Wifi Score Report.
6936      */
updateLinkLayerStatsRssiAndScoreReport()6937     private void updateLinkLayerStatsRssiAndScoreReport() {
6938         sendMessage(CMD_ONESHOT_RSSI_POLL);
6939     }
6940 
convertToUsabilityStatsTriggerType(int unusableEventTriggerType)6941     private int convertToUsabilityStatsTriggerType(int unusableEventTriggerType) {
6942         int triggerType;
6943         switch (unusableEventTriggerType) {
6944             case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
6945                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_BAD_TX;
6946                 break;
6947             case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
6948                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_TX_WITHOUT_RX;
6949                 break;
6950             case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
6951                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_BOTH;
6952                 break;
6953             case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
6954                 triggerType = WifiUsabilityStats.TYPE_FIRMWARE_ALERT;
6955                 break;
6956             case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST:
6957                 triggerType = WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST;
6958                 break;
6959             default:
6960                 triggerType = WifiUsabilityStats.TYPE_UNKNOWN;
6961                 Log.e(getTag(), "Unknown WifiIsUnusableEvent: " + unusableEventTriggerType);
6962         }
6963         return triggerType;
6964     }
6965 
6966     // Before transition to L3ProvisioningState, always shut down the current IpClient
6967     // instance and recreate a new IpClient and IpClientCallbacks instance, defer received
6968     // messages in this state except CMD_IPCLIENT_CREATED, recreation of a new IpClient
6969     // guarantees the out-of-date callbacks will be ignored, otherwise, it's not easy to
6970     // differentiate callbacks which comes from new IpClient or legacy IpClient. So far
6971     // only transit to this state iff IP reachability gets lost due to NUD failure.
6972     class WaitBeforeL3ProvisioningState extends RunnerState {
WaitBeforeL3ProvisioningState(int threshold)6973         WaitBeforeL3ProvisioningState(int threshold) {
6974             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
6975         }
6976 
6977         @Override
enterImpl()6978         public void enterImpl() {
6979             // Recreate a new IpClient instance.
6980             makeIpClient();
6981 
6982             // Given that {@link IpClientCallbacks#awaitCreation} is invoked when making a
6983             // IpClient instance, which waits for {@link IPCLIENT_STARTUP_TIMEOUT_MS}.
6984             // If await IpClient recreation times out, then send timeout message to proceed
6985             // to Disconnected state, otherwise, we will never exit this state.
6986             sendMessage(CMD_IPCLIENT_STARTUP_TIMEOUT);
6987         }
6988 
6989         @Override
exitImpl()6990         public void exitImpl() {
6991             removeMessages(CMD_IPCLIENT_STARTUP_TIMEOUT);
6992         }
6993 
6994         @Override
processMessageImpl(Message message)6995         public boolean processMessageImpl(Message message) {
6996             switch(message.what) {
6997                 case CMD_IPCLIENT_CREATED: {
6998                     if (!isFromCurrentIpClientCallbacks(message)) break;
6999                     mIpClient = (IpClientManager) message.obj;
7000                     transitionTo(mL3ProvisioningState);
7001                     break;
7002                 }
7003 
7004                 case CMD_IPCLIENT_STARTUP_TIMEOUT: {
7005                     Log.e(getTag(), "Fail to create an IpClient instance within "
7006                             + IPCLIENT_STARTUP_TIMEOUT_MS + "ms");
7007                     handleNetworkDisconnect(false,
7008                             WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_CREATE_IP_CLIENT_TIMEOUT);
7009                     transitionTo(mDisconnectedState);
7010                     break;
7011                 }
7012 
7013                 default:
7014                     // Do not process any other messages except CMD_IPCLIENT_CREATED and
7015                     // CMD_IPCLIENT_STARTUP_TIMEOUT. This means that this state can be very
7016                     // simple because it does not need to worry about messasge ordering.
7017                     // Re-creating IpClient should only take a few milliseconds, but in the
7018                     // worst case, this will result in the state machine not processing any
7019                     // messages for IPCLIENT_STARTUP_TIMEOUT_MS.
7020                     deferMessage(message);
7021             }
7022 
7023             logStateAndMessage(message, this);
7024             return HANDLED;
7025         }
7026 
7027         @Override
getMessageLogRec(int what)7028         public String getMessageLogRec(int what) {
7029             return ClientModeImpl.class.getSimpleName() + "."
7030                     + WaitBeforeL3ProvisioningState.class.getSimpleName() + "."
7031                     + getWhatToString(what);
7032         }
7033     }
7034 
7035     class L3ProvisioningState extends RunnerState {
7036 
onL3ProvisioningTimeout()7037         private void onL3ProvisioningTimeout() {
7038             logi("l3Provisioning Timeout, Configuring the network as local-only");
7039             mIpProvisioningTimedOut = true;
7040             mWifiConnectivityManager.handleConnectionStateChanged(
7041                     mClientModeManager,
7042                     WifiConnectivityManager.WIFI_STATE_CONNECTED);
7043             mWifiConfigManager.setIpProvisioningTimedOut(mLastNetworkId, true);
7044             sendNetworkChangeBroadcast(DetailedState.CONNECTED);
7045         };
7046 
L3ProvisioningState(int threshold)7047         L3ProvisioningState(int threshold) {
7048             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
7049         }
7050 
7051         @Override
enterImpl()7052         public void enterImpl() {
7053             startL3Provisioning();
7054             if (mContext.getResources().getBoolean(
7055                     R.bool.config_wifiRemainConnectedAfterIpProvisionTimeout)) {
7056                 sendMessageDelayed(obtainMessage(CMD_IP_PROVISIONING_TIMEOUT),
7057                         WAIT_FOR_L3_PROVISIONING_TIMEOUT_MS);
7058             }
7059         }
7060 
7061         @Override
exitImpl()7062         public void exitImpl() {
7063             mIpProvisioningTimedOut = false;
7064             removeMessages(CMD_IP_PROVISIONING_TIMEOUT);
7065             mWifiConfigManager.setIpProvisioningTimedOut(mLastNetworkId, false);
7066         }
7067 
7068         @Override
getMessageLogRec(int what)7069         public String getMessageLogRec(int what) {
7070             return ClientModeImpl.class.getSimpleName() + "."
7071                     + L3ProvisioningState.class.getSimpleName() + "." + getWhatToString(what);
7072         }
7073 
7074         @Override
processMessageImpl(Message message)7075         public boolean processMessageImpl(Message message) {
7076             boolean handleStatus = HANDLED;
7077 
7078             switch(message.what) {
7079                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: {
7080                     DisconnectEventInfo eventInfo = (DisconnectEventInfo) message.obj;
7081                     mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
7082                             getConnectingSsidInternal(),
7083                             !isValidBssid(eventInfo.bssid)
7084                             ? mTargetBssid : eventInfo.bssid,
7085                             WifiLastResortWatchdog.FAILURE_CODE_DHCP,
7086                             isConnected());
7087                     handleStatus = NOT_HANDLED;
7088                     break;
7089                 }
7090                 case CMD_IP_PROVISIONING_TIMEOUT: {
7091                     onL3ProvisioningTimeout();
7092                     break;
7093                 }
7094                 default: {
7095                     handleStatus = NOT_HANDLED;
7096                     break;
7097                 }
7098             }
7099 
7100             if (handleStatus == HANDLED) {
7101                 logStateAndMessage(message, this);
7102             }
7103             return handleStatus;
7104         }
7105 
startL3Provisioning()7106         private void startL3Provisioning() {
7107             WifiConfiguration currentConfig = getConnectedWifiConfigurationInternal();
7108             if (mIpClientWithPreConnection && mIpClient != null) {
7109                 mIpClient.notifyPreconnectionComplete(mSentHLPs);
7110                 mIpClientWithPreConnection = false;
7111                 mSentHLPs = false;
7112             } else {
7113                 startIpClient(currentConfig, false);
7114             }
7115             // Get Link layer stats so as we get fresh tx packet counters
7116             getWifiLinkLayerStats();
7117         }
7118     }
7119 
7120     /**
7121      * Helper function to check if a network has been recently selected by the user.
7122      * (i.e less than {@link #LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS) before).
7123      */
7124     @VisibleForTesting
isRecentlySelectedByTheUser(@onNull WifiConfiguration currentConfig)7125     public boolean isRecentlySelectedByTheUser(@NonNull WifiConfiguration currentConfig) {
7126         long currentTimeMillis = mClock.getElapsedSinceBootMillis();
7127         return mWifiConfigManager.getLastSelectedNetwork() == currentConfig.networkId
7128                 && currentTimeMillis - mWifiConfigManager.getLastSelectedTimeStamp()
7129                 < LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS;
7130     }
7131 
sendConnectedState()7132     private void sendConnectedState() {
7133         mNetworkAgent.markConnected();
7134         sendNetworkChangeBroadcast(DetailedState.CONNECTED);
7135     }
7136 
7137     class RoamingState extends RunnerState {
7138         boolean mAssociated;
7139 
RoamingState(int threshold)7140         RoamingState(int threshold) {
7141             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
7142         }
7143 
7144         @Override
enterImpl()7145         public void enterImpl() {
7146             if (mVerboseLoggingEnabled) {
7147                 log("RoamingState Enter mScreenOn=" + mScreenOn);
7148             }
7149 
7150             // Make sure we disconnect if roaming fails
7151             mRoamWatchdogCount++;
7152             logd("Start Roam Watchdog " + mRoamWatchdogCount);
7153             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
7154                     mRoamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
7155             mAssociated = false;
7156         }
7157 
7158         @Override
exitImpl()7159         public void exitImpl() {
7160         }
7161 
7162         @Override
getMessageLogRec(int what)7163         public String getMessageLogRec(int what) {
7164             return ClientModeImpl.class.getSimpleName() + "." + RoamingState.class.getSimpleName()
7165                     + "." + getWhatToString(what);
7166         }
7167 
7168         @Override
processMessageImpl(Message message)7169         public boolean processMessageImpl(Message message) {
7170             boolean handleStatus = HANDLED;
7171 
7172             switch (message.what) {
7173                 case CMD_IP_CONFIGURATION_LOST: {
7174                     WifiConfiguration config = getConnectedWifiConfigurationInternal();
7175                     if (config != null) {
7176                         mWifiDiagnostics.triggerBugReportDataCapture(
7177                                 WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
7178                     }
7179                     handleStatus = NOT_HANDLED;
7180                     break;
7181                 }
7182                 case CMD_UNWANTED_NETWORK: {
7183                     if (mVerboseLoggingEnabled) {
7184                         log("Roaming and CS doesn't want the network -> ignore");
7185                     }
7186                     break;
7187                 }
7188                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: {
7189                     /**
7190                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
7191                      * before NETWORK_DISCONNECTION_EVENT
7192                      * And there is an associated BSSID corresponding to our target BSSID, then
7193                      * we have missed the network disconnection, transition to mDisconnectedState
7194                      * and handle the rest of the events there.
7195                      */
7196                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7197                     SupplicantState state = handleSupplicantStateChange(stateChangeResult);
7198                     if (state == SupplicantState.DISCONNECTED
7199                             || state == SupplicantState.INACTIVE
7200                             || state == SupplicantState.INTERFACE_DISABLED) {
7201                         if (mVerboseLoggingEnabled) {
7202                             log("RoamingState: Supplicant State change " + stateChangeResult);
7203                         }
7204                         handleNetworkDisconnect(false,
7205                                 WIFI_DISCONNECT_REPORTED__FAILURE_CODE__SUPPLICANT_DISCONNECTED);
7206                         transitionTo(mDisconnectedState);
7207                     }
7208                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
7209                         // We completed the layer2 roaming part
7210                         mAssociated = true;
7211                         mTargetBssid = stateChangeResult.bssid;
7212                     }
7213                     break;
7214                 }
7215                 case CMD_ROAM_WATCHDOG_TIMER: {
7216                     if (mRoamWatchdogCount == message.arg1) {
7217                         if (mVerboseLoggingEnabled) log("roaming watchdog! -> disconnect");
7218                         mWifiMetrics.endConnectionEvent(
7219                                 mInterfaceName,
7220                                 WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
7221                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
7222                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN,
7223                                 mWifiInfo.getFrequency(), 0);
7224                         mRoamFailCount++;
7225                         handleNetworkDisconnect(false,
7226                                 WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__ROAM_WATCHDOG_TIMER);
7227                         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
7228                                 StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER);
7229                         mWifiNative.disconnect(mInterfaceName);
7230                         transitionTo(mDisconnectedState);
7231                     }
7232                     break;
7233                 }
7234                 case WifiMonitor.NETWORK_CONNECTION_EVENT: {
7235                     if (mAssociated) {
7236                         if (mVerboseLoggingEnabled) {
7237                             log("roaming and Network connection established");
7238                         }
7239                         NetworkConnectionEventInfo connectionInfo =
7240                                 (NetworkConnectionEventInfo) message.obj;
7241                         mLastNetworkId = connectionInfo.networkId;
7242                         mLastBssid = connectionInfo.bssid;
7243                         handleNetworkConnectionEventInfo(
7244                                 getConnectedWifiConfigurationInternal(), connectionInfo);
7245                         updateLayer2Information();
7246                         sendNetworkChangeBroadcastWithCurrentState();
7247                         updateCurrentConnectionInfo();
7248                         // Successful framework roam! (probably)
7249                         mWifiBlocklistMonitor.handleBssidConnectionSuccess(mLastBssid,
7250                                 mWifiInfo.getSSID());
7251                         reportConnectionAttemptEnd(
7252                                 WifiMetrics.ConnectionEvent.FAILURE_NONE,
7253                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
7254                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
7255 
7256                         // We must clear the config BSSID, as the wifi chipset may decide to roam
7257                         // from this point on and having the BSSID specified by QNS would cause
7258                         // the roam to fail and the device to disconnect.
7259                         // When transition from RoamingState to DisconnectedState, the config BSSID
7260                         // is cleared by handleNetworkDisconnect().
7261                         clearTargetBssid("RoamingCompleted");
7262 
7263                         // We used to transition to L3ProvisioningState in an
7264                         // attempt to do DHCPv4 RENEWs on framework roams.
7265                         // DHCP can take too long to time out, and we now rely
7266                         // upon IpClient's use of IpReachabilityMonitor to
7267                         // confirm our current network configuration.
7268                         //
7269                         // mIpClient.confirmConfiguration() is called within
7270                         // the handling of SupplicantState.COMPLETED.
7271                         transitionTo(mL3ConnectedState);
7272                     } else {
7273                         mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7274                     }
7275                     break;
7276                 }
7277                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: {
7278                     // Throw away but only if it corresponds to the network we're roaming to
7279                     DisconnectEventInfo eventInfo = (DisconnectEventInfo) message.obj;
7280                     if (true) {
7281                         String target = "";
7282                         if (mTargetBssid != null) target = mTargetBssid;
7283                         log("NETWORK_DISCONNECTION_EVENT in roaming state"
7284                                 + " BSSID=" + eventInfo.bssid
7285                                 + " target=" + target);
7286                     }
7287                     clearNetworkCachedDataIfNeeded(
7288                             getConnectingWifiConfigurationInternal(), eventInfo.reasonCode);
7289                     if (eventInfo.bssid.equals(mTargetBssid)) {
7290                         handleNetworkDisconnect(false, eventInfo.reasonCode);
7291                         transitionTo(mDisconnectedState);
7292                     }
7293                     break;
7294                 }
7295                 default: {
7296                     handleStatus = NOT_HANDLED;
7297                     break;
7298                 }
7299             }
7300 
7301             if (handleStatus == HANDLED) {
7302                 logStateAndMessage(message, this);
7303             }
7304             return handleStatus;
7305         }
7306 
7307         @Override
exit()7308         public void exit() {
7309             logd("ClientModeImpl: Leaving Roaming state");
7310         }
7311     }
7312 
7313     class L3ConnectedState extends RunnerState {
L3ConnectedState(int threshold)7314         L3ConnectedState(int threshold) {
7315             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
7316         }
7317 
7318         @Override
enterImpl()7319         public void enterImpl() {
7320             if (mVerboseLoggingEnabled) {
7321                 log("Enter ConnectedState  mScreenOn=" + mScreenOn);
7322             }
7323 
7324             reportConnectionAttemptEnd(
7325                     WifiMetrics.ConnectionEvent.FAILURE_NONE,
7326                     WifiMetricsProto.ConnectionEvent.HLF_NONE,
7327                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
7328             mWifiConnectivityManager.handleConnectionStateChanged(
7329                     mClientModeManager,
7330                     WifiConnectivityManager.WIFI_STATE_CONNECTED);
7331             registerConnected();
7332             mTargetWifiConfiguration = null;
7333             mWifiScoreReport.reset();
7334             mLastSignalLevel = -1;
7335 
7336             // Not roaming anymore
7337             mIsAutoRoaming = false;
7338 
7339             mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
7340             mWifiLastResortWatchdog.connectedStateTransition(true);
7341             mWifiStateTracker.updateState(mInterfaceName, WifiStateTracker.CONNECTED);
7342             // Inform WifiLockManager
7343             mWifiLockManager.updateWifiClientConnected(mClientModeManager, true);
7344             WifiConfiguration config = getConnectedWifiConfigurationInternal();
7345             mWifiScoreReport.startConnectedNetworkScorer(
7346                     mNetworkAgent.getNetwork().getNetId(), isRecentlySelectedByTheUser(config));
7347             mWifiScoreCard.noteIpConfiguration(mWifiInfo);
7348             // too many places to record L3 failure with too many failure reasons.
7349             // So only record success here.
7350             mWifiMetrics.noteFirstL3ConnectionAfterBoot(true);
7351             updateCurrentConnectionInfo();
7352             sendConnectedState();
7353             // Set the roaming policy for the currently connected network
7354             if (getClientRoleForMetrics(config)
7355                     != WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY) {
7356                 if (isPrimary()) {
7357                     mWifiInjector.getWifiRoamingModeManager().applyWifiRoamingMode(
7358                             mInterfaceName, mWifiInfo.getSSID());
7359                 }
7360                 if (SdkLevel.isAtLeastV() && mWifiInjector.getWifiVoipDetector() != null) {
7361                     mWifiInjector.getWifiVoipDetector().notifyWifiConnected(true,
7362                             isPrimary(), mInterfaceName);
7363                 }
7364             }
7365         }
7366 
7367         @Override
getMessageLogRec(int what)7368         public String getMessageLogRec(int what) {
7369             return ClientModeImpl.class.getSimpleName() + "."
7370                     + L3ConnectedState.class.getSimpleName() + "." + getWhatToString(what);
7371         }
7372 
7373         @Override
processMessageImpl(Message message)7374         public boolean processMessageImpl(Message message) {
7375             boolean handleStatus = HANDLED;
7376 
7377             switch (message.what) {
7378                 case CMD_UNWANTED_NETWORK: {
7379                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
7380                         mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_FRAMEWORK_DISCONNECT,
7381                                 StaEvent.DISCONNECT_UNWANTED);
7382                         if (mClientModeManager.getRole() == ROLE_CLIENT_SECONDARY_TRANSIENT
7383                                 && mClientModeManager.getPreviousRole() == ROLE_CLIENT_PRIMARY) {
7384                             mWifiMetrics.incrementMakeBeforeBreakLingerCompletedCount(
7385                                     mClock.getElapsedSinceBootMillis()
7386                                             - mClientModeManager.getLastRoleChangeSinceBootMs());
7387                         }
7388                         WifiConfiguration config = getConnectedWifiConfigurationInternal();
7389                         if (mWifiGlobals.disableUnwantedNetworkOnLowRssi() && isPrimary()
7390                                 && config != null && !isRecentlySelectedByTheUser(config)
7391                                 && config.getNetworkSelectionStatus()
7392                                 .getNetworkSelectionDisableReason()
7393                                     == DISABLED_NONE && mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
7394                                 && mWifiInfo.getRssi() < mScoringParams.getSufficientRssi(
7395                                         mWifiInfo.getFrequency())) {
7396                             if (mVerboseLoggingEnabled) {
7397                                 Log.i(getTag(), "CMD_UNWANTED_NETWORK update network "
7398                                         + config.networkId + " with DISABLED_UNWANTED_LOW_RSSI "
7399                                         + "under rssi:" + mWifiInfo.getRssi());
7400                             }
7401                             mWifiConfigManager.updateNetworkSelectionStatus(
7402                                     config.networkId,
7403                                     DISABLED_UNWANTED_LOW_RSSI);
7404                         }
7405                         mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_UNWANTED_BY_CONNECTIVITY;
7406                         mWifiNative.disconnect(mInterfaceName);
7407                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
7408                             || message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
7409                         Log.d(getTag(), (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
7410                                 ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
7411                                 : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
7412                         WifiConfiguration config = getConnectedWifiConfigurationInternal();
7413                         if (config != null) {
7414                             // Disable autojoin
7415                             if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
7416                                 mWifiConfigManager.setNetworkValidatedInternetAccess(
7417                                         config.networkId, false);
7418                                 WifiScoreCard.PerBssid perBssid = mWifiScoreCard.lookupBssid(
7419                                         mWifiInfo.getSSID(), mWifiInfo.getBSSID());
7420                                 int probInternet = perBssid.estimatePercentInternetAvailability();
7421                                 if (mVerboseLoggingEnabled) {
7422                                     Log.d(TAG, "Potentially disabling network due to no "
7423                                             + "internet. Probability of having internet = "
7424                                             + probInternet);
7425                                 }
7426                                 // Only permanently disable a network if probability of having
7427                                 // internet from the currently connected BSSID is less than 60%.
7428                                 // If there is no historically information of the current BSSID,
7429                                 // the probability of internet will default to 50%, and the network
7430                                 // will be permanently disabled.
7431                                 mWifiConfigManager.updateNetworkSelectionStatus(config.networkId,
7432                                         probInternet < PROBABILITY_WITH_INTERNET_TO_PERMANENTLY_DISABLE_NETWORK
7433                                                 ? DISABLED_NO_INTERNET_PERMANENT
7434                                                 : DISABLED_NO_INTERNET_TEMPORARY);
7435                             } else { // NETWORK_STATUS_UNWANTED_VALIDATION_FAILED
7436                                 // stop collect last-mile stats since validation fail
7437                                 mWifiDiagnostics.reportConnectionEvent(
7438                                         WifiDiagnostics.CONNECTION_EVENT_FAILED,
7439                                         mClientModeManager);
7440                                 mWifiConfigManager.incrementNetworkNoInternetAccessReports(
7441                                         config.networkId);
7442                                 if (!config.getNetworkSelectionStatus()
7443                                         .hasEverValidatedInternetAccess()
7444                                         && !config.noInternetAccessExpected) {
7445                                     mWifiConfigManager.updateNetworkSelectionStatus(
7446                                             config.networkId,
7447                                             DISABLED_NO_INTERNET_PERMANENT);
7448                                 } else if (!isRecentlySelectedByTheUser(config)
7449                                         && !config.noInternetAccessExpected) {
7450                                     // If this was not recently selected by the user, update network
7451                                     // selection status to temporarily disable the network.
7452                                     if (config.getNetworkSelectionStatus()
7453                                             .getNetworkSelectionDisableReason()
7454                                             != DISABLED_NO_INTERNET_PERMANENT) {
7455                                         Log.i(getTag(), "Temporarily disabling network "
7456                                                 + "because of no-internet access");
7457                                         mWifiConfigManager.updateNetworkSelectionStatus(
7458                                                 config.networkId,
7459                                                 DISABLED_NO_INTERNET_TEMPORARY);
7460                                     }
7461                                     mWifiBlocklistMonitor.handleBssidConnectionFailure(
7462                                             mLastBssid, config,
7463                                             WifiBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE,
7464                                             mWifiInfo.getRssi());
7465                                 }
7466                                 mWifiScoreCard.noteValidationFailure(mWifiInfo);
7467                                 mCmiMonitor.onInternetValidationFailed(mClientModeManager,
7468                                         mCurrentConnectionDetectedCaptivePortal);
7469                             }
7470                         }
7471                     }
7472                     break;
7473                 }
7474                 case CMD_NETWORK_STATUS: {
7475                     if (message.arg1 == NetworkAgent.VALIDATION_STATUS_VALID) {
7476                         // stop collect last-mile stats since validation pass
7477                         mWifiDiagnostics.reportConnectionEvent(
7478                                 WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED, mClientModeManager);
7479                         mWifiScoreCard.noteValidationSuccess(mWifiInfo);
7480                         mWifiBlocklistMonitor.handleNetworkValidationSuccess(mLastBssid,
7481                                 mWifiInfo.getSSID());
7482                         WifiConfiguration config = getConnectedWifiConfigurationInternal();
7483                         if (config != null) {
7484                             // re-enable autojoin
7485                             mWifiConfigManager.updateNetworkSelectionStatus(
7486                                     config.networkId,
7487                                     WifiConfiguration.NetworkSelectionStatus
7488                                             .DISABLED_NONE);
7489                             mWifiConfigManager.setNetworkValidatedInternetAccess(
7490                                     config.networkId, true);
7491                             if (config.isPasspoint()
7492                                     && mTermsAndConditionsUrl != null) {
7493                                 // Clear the T&C after the user accepted them and the we are
7494                                 // notified that the network validation is successful
7495                                 mTermsAndConditionsUrl = null;
7496                                 LinkProperties newLp = new LinkProperties(mLinkProperties);
7497                                 addPasspointInfoToLinkProperties(newLp);
7498                                 sendMessage(CMD_UPDATE_LINKPROPERTIES,
7499                                         mIpClientCallbacks.getCallbackIndex(), 0, newLp);
7500                                 mWifiMetrics
7501                                         .incrementTotalNumberOfPasspointAcceptanceOfTermsAndConditions();
7502                             }
7503                             if (retrieveConnectedNetworkDefaultGateway()) {
7504                                 updateLinkedNetworks(config);
7505                             }
7506                         }
7507                         mCmiMonitor.onInternetValidated(mClientModeManager);
7508                     }
7509                     break;
7510                 }
7511                 case CMD_ACCEPT_UNVALIDATED: {
7512                     boolean accept = (message.arg1 != 0);
7513                     mWifiConfigManager.setNetworkNoInternetAccessExpected(mLastNetworkId, accept);
7514                     break;
7515                 }
7516                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: {
7517                     DisconnectEventInfo eventInfo = (DisconnectEventInfo) message.obj;
7518                     reportConnectionAttemptEnd(
7519                             WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
7520                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
7521                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN,
7522                             eventInfo.reasonCode);
7523                     if (unexpectedDisconnectedReason(eventInfo.reasonCode)) {
7524                         mWifiDiagnostics.triggerBugReportDataCapture(
7525                                 WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
7526                     }
7527 
7528                     if (!eventInfo.locallyGenerated) {
7529                         // ignore disconnects initiated by wpa_supplicant.
7530                         mWifiScoreCard.noteNonlocalDisconnect(mInterfaceName, eventInfo.reasonCode);
7531                         int rssi = mWifiInfo.getRssi();
7532                         mWifiBlocklistMonitor.handleBssidConnectionFailure(mWifiInfo.getBSSID(),
7533                                 getConnectedWifiConfiguration(),
7534                                 WifiBlocklistMonitor.REASON_ABNORMAL_DISCONNECT, rssi);
7535                     }
7536                     WifiConfiguration config = getConnectedWifiConfigurationInternal();
7537 
7538                     if (mVerboseLoggingEnabled) {
7539                         log("NETWORK_DISCONNECTION_EVENT in connected state"
7540                                 + " BSSID=" + mWifiInfo.getBSSID()
7541                                 + " RSSI=" + mWifiInfo.getRssi()
7542                                 + " freq=" + mWifiInfo.getFrequency()
7543                                 + " reason=" + eventInfo.reasonCode
7544                                 + " Network Selection Status=" + (config == null ? "Unavailable"
7545                                 : config.getNetworkSelectionStatus().getNetworkStatusString()));
7546                     }
7547                     handleNetworkDisconnect(false, eventInfo.reasonCode);
7548                     transitionTo(mDisconnectedState);
7549                     break;
7550                 }
7551                 case CMD_START_ROAM: {
7552                     /* Connect command coming from auto-join */
7553                     int netId = message.arg1;
7554                     String bssid = (String) message.obj;
7555                     if (bssid == null) {
7556                         bssid = SUPPLICANT_BSSID_ANY;
7557                     }
7558                     WifiConfiguration config =
7559                             mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
7560                     if (config == null) {
7561                         loge("CMD_START_ROAM and no config, bail out...");
7562                         break;
7563                     }
7564                     mLastScanRssi = mWifiConfigManager.findScanRssi(netId,
7565                             mWifiHealthMonitor.getScanRssiValidTimeMs());
7566                     mWifiScoreCard.noteConnectionAttempt(mWifiInfo, mLastScanRssi, config.SSID);
7567                     setTargetBssid(config, bssid);
7568                     mTargetNetworkId = netId;
7569                     mWifiPseudonymManager.enableStrictConservativePeerModeIfSupported(config);
7570                     logd("CMD_START_ROAM sup state "
7571                             + " my state " + getCurrentState().getName()
7572                             + " nid=" + Integer.toString(netId)
7573                             + " config " + config.getProfileKey()
7574                             + " targetRoamBSSID " + mTargetBssid);
7575 
7576                     reportConnectionAttemptStart(config, mTargetBssid,
7577                             WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, Process.WIFI_UID);
7578                     if (mWifiNative.roamToNetwork(mInterfaceName, config)) {
7579                         mTargetWifiConfiguration = config;
7580                         mIsAutoRoaming = true;
7581                         mWifiMetrics.logStaEvent(
7582                                 mInterfaceName, StaEvent.TYPE_CMD_START_ROAM, config);
7583                         transitionTo(mRoamingState);
7584                     } else {
7585                         loge("CMD_START_ROAM Failed to start roaming to network " + config);
7586                         reportConnectionAttemptEnd(
7587                                 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7588                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
7589                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
7590                         mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7591                         break;
7592                     }
7593                     break;
7594                 }
7595                 case CMD_IP_CONFIGURATION_LOST: {
7596                     mWifiMetrics.incrementIpRenewalFailure();
7597                     handleStatus = NOT_HANDLED;
7598                     break;
7599                 }
7600                 default: {
7601                     handleStatus = NOT_HANDLED;
7602                     break;
7603                 }
7604             }
7605 
7606             if (handleStatus == HANDLED) {
7607                 logStateAndMessage(message, this);
7608             }
7609 
7610             return handleStatus;
7611         }
7612 
7613         @Override
exitImpl()7614         public void exitImpl() {
7615             logd("ClientModeImpl: Leaving Connected state");
7616             mWifiConnectivityManager.handleConnectionStateChanged(
7617                     mClientModeManager,
7618                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7619 
7620             mWifiLastResortWatchdog.connectedStateTransition(false);
7621             // Always notify Voip detector module.
7622             if (SdkLevel.isAtLeastV() && mWifiInjector.getWifiVoipDetector() != null) {
7623                 mWifiInjector.getWifiVoipDetector().notifyWifiConnected(false,
7624                         isPrimary(), mInterfaceName);
7625             }
7626         }
7627     }
7628 
7629     class DisconnectedState extends RunnerState {
DisconnectedState(int threshold)7630         DisconnectedState(int threshold) {
7631             super(threshold, mWifiInjector.getWifiHandlerLocalLog());
7632         }
7633 
7634         @Override
enterImpl()7635         public void enterImpl() {
7636             Log.i(getTag(), "disconnectedstate enter");
7637             // We don't scan frequently if this is a temporary disconnect
7638             // due to p2p
7639             if (mWifiP2pConnection.shouldTemporarilyDisconnectWifi()) {
7640                 // TODO(b/161569371): P2P should wait for all ClientModeImpls to enter
7641                 //  DisconnectedState, not just one instance.
7642                 // (Does P2P Service support STA+P2P concurrency?)
7643                 mWifiP2pConnection.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
7644                 return;
7645             }
7646 
7647             if (mVerboseLoggingEnabled) {
7648                 logd(" Enter DisconnectedState screenOn=" + mScreenOn);
7649             }
7650 
7651             /** clear the roaming state, if we were roaming, we failed */
7652             mIsAutoRoaming = false;
7653             mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
7654 
7655             mWifiConnectivityManager.handleConnectionStateChanged(
7656                     mClientModeManager,
7657                     WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
7658 
7659             if (mDeviceConfigFacade.isOobPseudonymEnabled()) {
7660                 if (mVerboseLoggingEnabled) {
7661                     logd("unregister PseudonymUpdatingListener");
7662                 }
7663                 // unregister it any way, if it was not registered, it's no OP.
7664                 mWifiPseudonymManager
7665                         .unregisterPseudonymUpdatingListener(mPseudonymUpdatingListener);
7666             }
7667         }
7668 
7669         @Override
getMessageLogRec(int what)7670         public String getMessageLogRec(int what) {
7671             return ClientModeImpl.class.getSimpleName() + "."
7672                     + DisconnectedState.class.getSimpleName() + "." + getWhatToString(what);
7673         }
7674 
7675         @Override
processMessageImpl(Message message)7676         public boolean processMessageImpl(Message message) {
7677             boolean handleStatus = HANDLED;
7678 
7679             switch (message.what) {
7680                 case CMD_RECONNECT:
7681                 case CMD_REASSOCIATE: {
7682                     if (mWifiP2pConnection.shouldTemporarilyDisconnectWifi()) {
7683                         // Drop a third party reconnect/reassociate if STA is
7684                         // temporarily disconnected for p2p
7685                         break;
7686                     } else {
7687                         // ConnectableState handles it
7688                         handleStatus = NOT_HANDLED;
7689                     }
7690                     break;
7691                 }
7692                 default: {
7693                     handleStatus = NOT_HANDLED;
7694                     break;
7695                 }
7696             }
7697 
7698             if (handleStatus == HANDLED) {
7699                 logStateAndMessage(message, this);
7700             }
7701             return handleStatus;
7702         }
7703 
7704         @Override
exitImpl()7705         public void exitImpl() {
7706             mWifiConnectivityManager.handleConnectionStateChanged(
7707                     mClientModeManager,
7708                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7709         }
7710     }
7711 
handleGsmAuthRequest(SimAuthRequestData requestData)7712     void handleGsmAuthRequest(SimAuthRequestData requestData) {
7713         WifiConfiguration requestingWifiConfiguration = null;
7714         if (mTargetWifiConfiguration != null
7715                 && mTargetWifiConfiguration.networkId
7716                 == requestData.networkId) {
7717             requestingWifiConfiguration = mTargetWifiConfiguration;
7718             logd("id matches targetWifiConfiguration");
7719         } else if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
7720                 && mLastNetworkId == requestData.networkId) {
7721             requestingWifiConfiguration = getConnectedWifiConfigurationInternal();
7722             logd("id matches currentWifiConfiguration");
7723         }
7724 
7725         if (requestingWifiConfiguration == null) {
7726             logd("GsmAuthRequest received with null target/current WifiConfiguration.");
7727             return;
7728         }
7729 
7730         /*
7731          * Try authentication in the following order.
7732          *
7733          *    Standard       Cellular_auth     Type Command
7734          *
7735          * 1. 3GPP TS 31.102 3G_authentication [Length][RAND][Length][AUTN]
7736          *                            [Length][RES][Length][CK][Length][IK] and more
7737          * 2. 3GPP TS 31.102 2G_authentication [Length][RAND]
7738          *                            [Length][SRES][Length][Cipher Key Kc]
7739          * 3. 3GPP TS 11.11  2G_authentication [RAND]
7740          *                            [SRES][Cipher Key Kc]
7741          */
7742         String response = mWifiCarrierInfoManager
7743                 .getGsmSimAuthResponse(requestData.data, requestingWifiConfiguration);
7744         if (response == null) {
7745             // In case of failure, issue may be due to sim type, retry as No.2 case
7746             response = mWifiCarrierInfoManager
7747                     .getGsmSimpleSimAuthResponse(requestData.data, requestingWifiConfiguration);
7748             if (response == null) {
7749                 // In case of failure, issue may be due to sim type, retry as No.3 case
7750                 response = mWifiCarrierInfoManager.getGsmSimpleSimNoLengthAuthResponse(
7751                                 requestData.data, requestingWifiConfiguration);
7752             }
7753         }
7754         if (response == null || response.length() == 0) {
7755             mWifiNative.simAuthFailedResponse(mInterfaceName);
7756         } else {
7757             logv("Supplicant Response -" + response);
7758             mWifiNative.simAuthResponse(
7759                     mInterfaceName, WifiNative.SIM_AUTH_RESP_TYPE_GSM_AUTH, response);
7760         }
7761     }
7762 
handle3GAuthRequest(SimAuthRequestData requestData)7763     void handle3GAuthRequest(SimAuthRequestData requestData) {
7764         WifiConfiguration requestingWifiConfiguration = null;
7765         if (mTargetWifiConfiguration != null
7766                 && mTargetWifiConfiguration.networkId
7767                 == requestData.networkId) {
7768             requestingWifiConfiguration = mTargetWifiConfiguration;
7769             logd("id matches targetWifiConfiguration");
7770         } else if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
7771                 && mLastNetworkId == requestData.networkId) {
7772             requestingWifiConfiguration = getConnectedWifiConfigurationInternal();
7773             logd("id matches currentWifiConfiguration");
7774         }
7775 
7776         if (requestingWifiConfiguration == null) {
7777             logd("3GAuthRequest received with null target/current WifiConfiguration.");
7778             return;
7779         }
7780 
7781         SimAuthResponseData response = mWifiCarrierInfoManager
7782                 .get3GAuthResponse(requestData, requestingWifiConfiguration);
7783         if (response != null) {
7784             mWifiNative.simAuthResponse(
7785                     mInterfaceName, response.type, response.response);
7786         } else {
7787             mWifiNative.umtsAuthFailedResponse(mInterfaceName);
7788         }
7789     }
7790 
7791     /**
7792      * Automatically connect to the network specified
7793      *
7794      * @param networkId ID of the network to connect to
7795      * @param uid UID of the app triggering the connection.
7796      * @param bssid BSSID of the network
7797      */
startConnectToNetwork(int networkId, int uid, String bssid)7798     public void startConnectToNetwork(int networkId, int uid, String bssid) {
7799         sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
7800     }
7801 
7802     /**
7803      * Automatically roam to the network specified
7804      *
7805      * @param networkId ID of the network to roam to
7806      * @param bssid BSSID of the access point to roam to.
7807      */
startRoamToNetwork(int networkId, String bssid)7808     public void startRoamToNetwork(int networkId, String bssid) {
7809         sendMessage(CMD_START_ROAM, networkId, 0, bssid);
7810     }
7811 
7812     /**
7813      * @param reason reason code from supplicant on network disconnected event
7814      * @return true if this is a suspicious disconnect
7815      */
unexpectedDisconnectedReason(int reason)7816     static boolean unexpectedDisconnectedReason(int reason) {
7817         return reason == StaIfaceReasonCode.PREV_AUTH_NOT_VALID
7818                 || reason == StaIfaceReasonCode.CLASS2_FRAME_FROM_NONAUTH_STA
7819                 || reason == StaIfaceReasonCode.CLASS3_FRAME_FROM_NONASSOC_STA
7820                 || reason == StaIfaceReasonCode.DISASSOC_STA_HAS_LEFT
7821                 || reason == StaIfaceReasonCode.STA_REQ_ASSOC_WITHOUT_AUTH
7822                 || reason == StaIfaceReasonCode.MICHAEL_MIC_FAILURE
7823                 || reason == StaIfaceReasonCode.FOURWAY_HANDSHAKE_TIMEOUT
7824                 || reason == StaIfaceReasonCode.GROUP_KEY_UPDATE_TIMEOUT
7825                 || reason == StaIfaceReasonCode.GROUP_CIPHER_NOT_VALID
7826                 || reason == StaIfaceReasonCode.PAIRWISE_CIPHER_NOT_VALID
7827                 || reason == StaIfaceReasonCode.IEEE_802_1X_AUTH_FAILED
7828                 || reason == StaIfaceReasonCode.DISASSOC_LOW_ACK;
7829     }
7830 
getLinkPropertiesSummary(LinkProperties lp)7831     private static String getLinkPropertiesSummary(LinkProperties lp) {
7832         List<String> attributes = new ArrayList<>(6);
7833         if (lp.hasIpv4Address()) {
7834             attributes.add("v4");
7835         }
7836         if (lp.hasIpv4DefaultRoute()) {
7837             attributes.add("v4r");
7838         }
7839         if (lp.hasIpv4DnsServer()) {
7840             attributes.add("v4dns");
7841         }
7842         if (lp.hasGlobalIpv6Address()) {
7843             attributes.add("v6");
7844         }
7845         if (lp.hasIpv6DefaultRoute()) {
7846             attributes.add("v6r");
7847         }
7848         if (lp.hasIpv6DnsServer()) {
7849             attributes.add("v6dns");
7850         }
7851 
7852         return TextUtils.join(" ", attributes);
7853     }
7854 
7855     /**
7856      * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
7857      * This should match the network config framework is attempting to connect to.
7858      */
getConnectingSsidInternal()7859     private String getConnectingSsidInternal() {
7860         WifiConfiguration config = getConnectingWifiConfigurationInternal();
7861         return config != null ? config.SSID : null;
7862     }
7863 
7864     /**
7865      * Check if there is any connection request for WiFi network.
7866      */
hasConnectionRequests()7867     private boolean hasConnectionRequests() {
7868         return mNetworkFactory.hasConnectionRequests()
7869                 || mUntrustedNetworkFactory.hasConnectionRequests()
7870                 || mOemWifiNetworkFactory.hasConnectionRequests()
7871                 || mRestrictedWifiNetworkFactory.hasConnectionRequests()
7872                 || mMultiInternetManager.hasPendingConnectionRequests();
7873     }
7874 
7875     /**
7876      * Retrieve the factory MAC address from config store (stored on first bootup). If we don't have
7877      * a factory MAC address stored in config store, retrieve it now and store it.
7878      *
7879      * Note:
7880      * <li> Retries added to deal with any transient failures when invoking
7881      * {@link WifiNative#getStaFactoryMacAddress(String)}.
7882      */
7883     @Nullable
retrieveFactoryMacAddressAndStoreIfNecessary()7884     private MacAddress retrieveFactoryMacAddressAndStoreIfNecessary() {
7885         boolean saveFactoryMacInConfigStore =
7886                 mWifiGlobals.isSaveFactoryMacToConfigStoreEnabled();
7887         if (saveFactoryMacInConfigStore) {
7888             // Already present, just return.
7889             String factoryMacAddressStr = mSettingsConfigStore.get(isPrimary()
7890                     ? WIFI_STA_FACTORY_MAC_ADDRESS : SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS);
7891             if (factoryMacAddressStr != null) return MacAddress.fromString(factoryMacAddressStr);
7892         }
7893         MacAddress factoryMacAddress = mWifiNative.getStaFactoryMacAddress(mInterfaceName);
7894         if (factoryMacAddress == null) {
7895             // the device may be running an older HAL (version < 1.3).
7896             Log.w(TAG, (isPrimary() ? "Primary" : "Secondary")
7897                     + " failed to retrieve factory MAC address");
7898             return null;
7899         }
7900         if (saveFactoryMacInConfigStore) {
7901             mSettingsConfigStore.put(isPrimary()
7902                             ? WIFI_STA_FACTORY_MAC_ADDRESS : SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS,
7903                     factoryMacAddress.toString());
7904             Log.i(TAG, (isPrimary() ? "Primary" : "Secondary")
7905                     + " factory MAC address stored in config store: " + factoryMacAddress);
7906         }
7907         Log.i(TAG, (isPrimary() ? "Primary" : "Secondary")
7908                 + " factory MAC address retrieved: " + factoryMacAddress);
7909         return factoryMacAddress;
7910     }
7911 
7912     /**
7913      * Gets the factory MAC address of wlan0 (station interface).
7914      * @return String representation of the factory MAC address.
7915      */
7916     @Nullable
getFactoryMacAddress()7917     public String getFactoryMacAddress() {
7918         MacAddress factoryMacAddress = retrieveFactoryMacAddressAndStoreIfNecessary();
7919         if (factoryMacAddress != null) return factoryMacAddress.toString();
7920 
7921         // For devices with older HAL's (version < 1.3), no API exists to retrieve factory MAC
7922         // address (and also does not support MAC randomization - needs verson 1.2). So, just
7923         // return the regular MAC address from the interface.
7924         if (!mWifiGlobals.isConnectedMacRandomizationEnabled()) {
7925             Log.w(TAG, "Can't get factory MAC address, return the MAC address");
7926             return mWifiNative.getMacAddress(mInterfaceName);
7927         }
7928         return null;
7929     }
7930 
7931     /** Sends a link probe. */
probeLink(LinkProbeCallback callback, int mcs)7932     public void probeLink(LinkProbeCallback callback, int mcs) {
7933         String bssid = mWifiInfo.getBSSID();
7934         if (bssid == null) {
7935             Log.w(getTag(), "Attempted to send link probe when not connected!");
7936             callback.onFailure(LinkProbeCallback.LINK_PROBE_ERROR_NOT_CONNECTED);
7937             return;
7938         }
7939         mWifiNative.probeLink(mInterfaceName, MacAddress.fromString(bssid), callback, mcs);
7940     }
7941 
7942     private static class ConnectNetworkMessage {
7943         public final NetworkUpdateResult result;
7944         public final ActionListenerWrapper listener;
7945         public final String packageName;
7946         public final String attributionTag;
7947 
ConnectNetworkMessage(NetworkUpdateResult result, ActionListenerWrapper listener, String packageName, @Nullable String attributionTag)7948         ConnectNetworkMessage(NetworkUpdateResult result, ActionListenerWrapper listener,
7949                 String packageName, @Nullable String attributionTag) {
7950             this.result = result;
7951             this.listener = listener;
7952             this.packageName = packageName;
7953             this.attributionTag = attributionTag;
7954         }
7955     }
7956 
7957     /** Trigger network connection and provide status via the provided callback. */
connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName, @Nullable String attributionTag)7958     public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper,
7959             int callingUid, @NonNull String packageName, @Nullable String attributionTag) {
7960         Message message =
7961                 obtainMessage(CMD_CONNECT_NETWORK,
7962                         new ConnectNetworkMessage(result, wrapper, packageName, attributionTag));
7963         message.sendingUid = callingUid;
7964         sendMessage(message);
7965     }
7966 
7967     /** Trigger network save and provide status via the provided callback. */
saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName)7968     public void saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper,
7969             int callingUid, @NonNull String packageName) {
7970         Message message =
7971                 obtainMessage(CMD_SAVE_NETWORK,
7972                         new ConnectNetworkMessage(result, wrapper, packageName, null));
7973         message.sendingUid = callingUid;
7974         sendMessage(message);
7975     }
7976 
7977     /**
7978      * Handle BSS transition request from Connected BSS.
7979      *
7980      * @param frameData Data retrieved from received BTM request frame.
7981      */
handleBssTransitionRequest(BtmFrameData frameData)7982     private void handleBssTransitionRequest(BtmFrameData frameData) {
7983         if (frameData == null) {
7984             return;
7985         }
7986 
7987         String bssid = mWifiInfo.getBSSID();
7988         String ssid = mWifiInfo.getSSID();
7989         if ((bssid == null) || (ssid == null) || WifiManager.UNKNOWN_SSID.equals(ssid)) {
7990             Log.e(getTag(), "Failed to handle BSS transition: bssid: " + bssid + " ssid: " + ssid);
7991             return;
7992         }
7993 
7994         mWifiMetrics.incrementSteeringRequestCount();
7995 
7996         if ((frameData.mBssTmDataFlagsMask
7997                 & MboOceConstants.BTM_DATA_FLAG_MBO_CELL_DATA_CONNECTION_PREFERENCE_INCLUDED)
7998                 != 0) {
7999             mWifiMetrics.incrementMboCellularSwitchRequestCount();
8000         }
8001 
8002 
8003         if ((frameData.mBssTmDataFlagsMask
8004                 & MboOceConstants.BTM_DATA_FLAG_DISASSOCIATION_IMMINENT) != 0) {
8005             long duration = 0;
8006             if ((frameData.mBssTmDataFlagsMask
8007                     & MboOceConstants.BTM_DATA_FLAG_MBO_ASSOC_RETRY_DELAY_INCLUDED) != 0) {
8008                 mWifiMetrics.incrementSteeringRequestCountIncludingMboAssocRetryDelay();
8009                 duration = frameData.mBlockListDurationMs;
8010             }
8011             if (duration == 0) {
8012                 /*
8013                  * When disassoc imminent bit alone is set or MBO assoc retry delay is
8014                  * set to zero(reserved as per spec), blocklist the BSS for sometime to
8015                  * avoid AP rejecting the re-connect request.
8016                  */
8017                 duration = MboOceConstants.DEFAULT_BLOCKLIST_DURATION_MS;
8018             }
8019             // Blocklist the current BSS
8020             WifiConfiguration config = getConnectedWifiConfiguration();
8021             if (config == null) {
8022                 config = getConnectingWifiConfiguration();
8023             }
8024             mWifiBlocklistMonitor.blockBssidForDurationMs(bssid, config, duration,
8025                     WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_MBO_OCE, 0);
8026         }
8027 
8028         if (frameData.mStatus != MboOceConstants.BTM_RESPONSE_STATUS_ACCEPT) {
8029             // Trigger the network selection and re-connect to new network if available.
8030             mWifiMetrics.incrementForceScanCountDueToSteeringRequest();
8031             mWifiConnectivityManager.forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
8032         }
8033     }
8034 
8035     /**
8036      * @return true if this device supports FILS-SHA256
8037      */
isFilsSha256Supported()8038     private boolean isFilsSha256Supported() {
8039         return (getSupportedFeatures() & WIFI_FEATURE_FILS_SHA256) != 0;
8040     }
8041 
8042     /**
8043      * @return true if this device supports FILS-SHA384
8044      */
isFilsSha384Supported()8045     private boolean isFilsSha384Supported() {
8046         return (getSupportedFeatures() & WIFI_FEATURE_FILS_SHA384) != 0;
8047     }
8048 
8049     /**
8050      * @return true if this device supports Trust On First Use
8051      */
isTrustOnFirstUseSupported()8052     private boolean isTrustOnFirstUseSupported() {
8053         return (getSupportedFeatures() & WIFI_FEATURE_TRUST_ON_FIRST_USE) != 0;
8054     }
8055 
8056     /**
8057      * Helper method to set the allowed key management schemes from
8058      * scan result.
8059      * When the AKM is updated, changes should be propagated to the
8060      * actual saved network, and the correct AKM could be retrieved
8061      * on selecting the security params.
8062      */
updateAllowedKeyManagementSchemesFromScanResult( WifiConfiguration config, ScanResult scanResult)8063     private void updateAllowedKeyManagementSchemesFromScanResult(
8064             WifiConfiguration config, ScanResult scanResult) {
8065         config.enableFils(
8066                 isFilsSha256Supported()
8067                 && ScanResultUtil.isScanResultForFilsSha256Network(scanResult),
8068                 isFilsSha384Supported()
8069                 && ScanResultUtil.isScanResultForFilsSha384Network(scanResult));
8070         mWifiConfigManager.updateFilsAkms(config.networkId,
8071                 config.isFilsSha256Enabled(), config.isFilsSha384Enabled());
8072     }
8073     /**
8074      * Update wifi configuration based on the matching scan result.
8075      *
8076      * @param config Wifi configuration object.
8077      * @param scanResult Scan result matching the network.
8078      */
updateWifiConfigFromMatchingScanResult(WifiConfiguration config, ScanResult scanResult)8079     private void updateWifiConfigFromMatchingScanResult(WifiConfiguration config,
8080             ScanResult scanResult) {
8081         updateAllowedKeyManagementSchemesFromScanResult(config, scanResult);
8082         if (config.isFilsSha256Enabled() || config.isFilsSha384Enabled()) {
8083             config.enterpriseConfig.setFieldValue(WifiEnterpriseConfig.EAP_ERP, "1");
8084         }
8085     }
8086 
selectCandidateSecurityParamsIfNecessary( WifiConfiguration config, List<ScanResult> scanResults)8087     private void selectCandidateSecurityParamsIfNecessary(
8088             WifiConfiguration config,
8089             List<ScanResult> scanResults) {
8090         if (null != config.getNetworkSelectionStatus().getCandidateSecurityParams()) return;
8091         if (mVerboseLoggingEnabled) {
8092             Log.d(getTag(), "Select candidate security params for " + config.getProfileKey());
8093         }
8094 
8095         // This comes from wifi picker directly so there is no candidate security params.
8096         // Run network selection against this SSID.
8097         List<ScanDetail> scanDetailsList = scanResults.stream()
8098                 .filter(scanResult -> config.SSID.equals(
8099                         ScanResultUtil.createQuotedSsid(scanResult.SSID)))
8100                 .map(ScanDetail::new)
8101                 .collect(Collectors.toList());
8102         List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector
8103                 .getCandidatesForUserSelection(config, scanDetailsList);
8104         mWifiNetworkSelector.selectNetwork(candidates);
8105 
8106         SecurityParams params = null;
8107         // Get the fresh copy again to retrieve the candidate security params.
8108         WifiConfiguration freshConfig = mWifiConfigManager.getConfiguredNetwork(config.networkId);
8109         if (null != freshConfig
8110                 && null != freshConfig.getNetworkSelectionStatus().getCandidateSecurityParams()) {
8111             params = freshConfig.getNetworkSelectionStatus().getCandidateSecurityParams();
8112             Log.i(getTag(), "Select best-fit security params: " + params.getSecurityType());
8113         } else if (null != config.getNetworkSelectionStatus().getLastUsedSecurityParams()
8114                 && config.getNetworkSelectionStatus().getLastUsedSecurityParams().isEnabled()) {
8115             params = config.getNetworkSelectionStatus().getLastUsedSecurityParams();
8116             Log.i(getTag(), "Select the last used security params: " + params.getSecurityType());
8117         } else {
8118             params = config.getSecurityParamsList().stream()
8119                     .filter(WifiConfigurationUtil::isSecurityParamsValid)
8120                     .findFirst().orElse(null);
8121             if (null != params) {
8122                 Log.i(getTag(), "Select the first available security params: "
8123                         + params.getSecurityType());
8124             } else {
8125                 Log.w(getTag(), "No available security params.");
8126             }
8127         }
8128 
8129         config.getNetworkSelectionStatus().setCandidateSecurityParams(params);
8130         // populate the target security params to the internal configuration manually,
8131         // and then wifi info could retrieve this information.
8132         mWifiConfigManager.setNetworkCandidateScanResult(
8133                 config.networkId,
8134                 freshConfig == null ? null : freshConfig.getNetworkSelectionStatus().getCandidate(),
8135                 0, params);
8136     }
8137 
8138     /**
8139      * Update the wifi configuration before sending connect to
8140      * supplicant/driver.
8141      *
8142      * @param config wifi configuration object.
8143      * @param bssid BSSID to assocaite with.
8144      */
updateWifiConfigOnStartConnection(WifiConfiguration config, String bssid)8145     void updateWifiConfigOnStartConnection(WifiConfiguration config, String bssid) {
8146         setTargetBssid(config, bssid);
8147 
8148         // Go through the matching scan results and update wifi config.
8149         ScanResultMatchInfo key1 = ScanResultMatchInfo.fromWifiConfiguration(config);
8150         List<ScanResult> scanResults = mScanRequestProxy.getScanResults();
8151         for (ScanResult scanResult : scanResults) {
8152             if (!config.SSID.equals(ScanResultUtil.createQuotedSsid(scanResult.SSID))) {
8153                 continue;
8154             }
8155             ScanResultMatchInfo key2 = ScanResultMatchInfo.fromScanResult(scanResult);
8156             if (!key1.equals(key2)) {
8157                 continue;
8158             }
8159             updateWifiConfigFromMatchingScanResult(config, scanResult);
8160         }
8161 
8162         selectCandidateSecurityParamsIfNecessary(config, scanResults);
8163 
8164         if (mWifiGlobals.isConnectedMacRandomizationEnabled()) {
8165             boolean isMacRandomizationForceDisabled = isMacRandomizationForceDisabledOnSsid(config);
8166             if (config.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE
8167                     || isMacRandomizationForceDisabled) {
8168                 setCurrentMacToFactoryMac(config);
8169             } else {
8170                 configureRandomizedMacAddress(config);
8171             }
8172             if (isMacRandomizationForceDisabled
8173                     && config.macRandomizationSetting != WifiConfiguration.RANDOMIZATION_NONE) {
8174                 // update WifiConfigManager to disable MAC randomization so Settings show the right
8175                 // MAC randomization information.
8176                 config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
8177                 mWifiConfigManager.addOrUpdateNetwork(config, Process.SYSTEM_UID);
8178             }
8179         }
8180 
8181         if (config.enterpriseConfig != null
8182                 && config.enterpriseConfig.isAuthenticationSimBased()
8183                 && mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(
8184                 mWifiCarrierInfoManager.getBestMatchSubscriptionId(config))
8185                 && TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) {
8186             String anonAtRealm = mWifiCarrierInfoManager
8187                     .getAnonymousIdentityWith3GppRealm(config);
8188             // Use anonymous@<realm> when pseudonym is not available
8189             config.enterpriseConfig.setAnonymousIdentity(anonAtRealm);
8190         }
8191     }
8192 
isMacRandomizationForceDisabledOnSsid(WifiConfiguration config)8193     private boolean isMacRandomizationForceDisabledOnSsid(WifiConfiguration config) {
8194         Set<String> unsupportedSsids = new ArraySet<>(mContext.getResources().getStringArray(
8195                 R.array.config_wifiForceDisableMacRandomizationSsidList));
8196         Set<String> unsupportedPrefixes = mWifiGlobals.getMacRandomizationUnsupportedSsidPrefixes();
8197         boolean isUnsupportedByPrefix =
8198                 unsupportedPrefixes.stream().anyMatch(ssid -> config.SSID.startsWith(ssid));
8199         return isUnsupportedByPrefix || unsupportedSsids.contains(config.SSID);
8200     }
8201 
setConfigurationsPriorToIpClientProvisioning(WifiConfiguration config)8202     private void setConfigurationsPriorToIpClientProvisioning(WifiConfiguration config) {
8203         mIpClient.setHttpProxy(config.getHttpProxy());
8204         if (!TextUtils.isEmpty(mContext.getResources().getString(
8205                 R.string.config_wifi_tcp_buffers))) {
8206             mIpClient.setTcpBufferSizes(mContext.getResources().getString(
8207                     R.string.config_wifi_tcp_buffers));
8208         }
8209     }
8210 
startIpClient(WifiConfiguration config, boolean isFilsConnection)8211     private boolean startIpClient(WifiConfiguration config, boolean isFilsConnection) {
8212         if (mIpClient == null || config == null) {
8213             return false;
8214         }
8215 
8216         final boolean isUsingStaticIp =
8217                 (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
8218         final boolean isUsingMacRandomization =
8219                 config.macRandomizationSetting
8220                         != WifiConfiguration.RANDOMIZATION_NONE
8221                         && mWifiGlobals.isConnectedMacRandomizationEnabled();
8222         final List<byte[]> ouis = getOuiInternal(config);
8223         final List<android.net.DhcpOption> options =
8224                 mWifiConfigManager.getCustomDhcpOptions(WifiSsid.fromString(config.SSID), ouis);
8225         if (mVerboseLoggingEnabled) {
8226             final String key = config.getProfileKey();
8227             log("startIpClient netId=" + Integer.toString(mLastNetworkId)
8228                     + " " + key + " "
8229                     + " roam=" + mIsAutoRoaming
8230                     + " static=" + isUsingStaticIp
8231                     + " randomMac=" + isUsingMacRandomization
8232                     + " isFilsConnection=" + isFilsConnection);
8233         }
8234 
8235         final MacAddress currentBssid = getCurrentBssidInternalMacAddress();
8236         final String l2Key = mLastL2KeyAndGroupHint != null
8237                 ? mLastL2KeyAndGroupHint.first : null;
8238         final String groupHint = mLastL2KeyAndGroupHint != null
8239                 ? mLastL2KeyAndGroupHint.second : null;
8240         final Layer2Information layer2Info = new Layer2Information(l2Key, groupHint,
8241                 currentBssid);
8242 
8243         final ProvisioningConfiguration.Builder prov =
8244                 new ProvisioningConfiguration.Builder()
8245                         .withDisplayName(config.SSID)
8246                         .withCreatorUid(config.creatorUid)
8247                         .withLayer2Information(layer2Info)
8248                         .withDhcpOptions(convertToInternalDhcpOptions(options));
8249         if (isUsingMacRandomization) {
8250             // Use EUI64 address generation for link-local IPv6 addresses.
8251             prov.withRandomMacAddress();
8252         }
8253         if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)
8254                 || isPrimary()) {
8255             // unclear if the native layer will return the correct non-capabilities if APF is
8256             // not supported on secondary interfaces.
8257             prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
8258         }
8259         if (SdkLevel.isAtLeastV()) {
8260             // Set the user dhcp hostname setting.
8261             int hostnameSetting = config.isSendDhcpHostnameEnabled()
8262                     ? IIpClient.HOSTNAME_SETTING_SEND
8263                     : IIpClient.HOSTNAME_SETTING_DO_NOT_SEND;
8264             int restrictions = mWifiGlobals.getSendDhcpHostnameRestriction();
8265             // Override the user setting the dhcp hostname restrictions.
8266             if (config.isOpenNetwork()) {
8267                 if ((restrictions
8268                         & WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN) != 0) {
8269                     hostnameSetting = IIpClient.HOSTNAME_SETTING_DO_NOT_SEND;
8270                 }
8271             } else {
8272                 if ((restrictions
8273                         & WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE) != 0) {
8274                     hostnameSetting = IIpClient.HOSTNAME_SETTING_DO_NOT_SEND;
8275                 }
8276             }
8277             prov.withHostnameSetting(hostnameSetting);
8278         }
8279         if (isFilsConnection) {
8280             stopIpClient();
8281             if (isUsingStaticIp) {
8282                 mWifiNative.flushAllHlp(mInterfaceName);
8283                 return false;
8284             }
8285             setConfigurationsPriorToIpClientProvisioning(config);
8286             prov.withPreconnection()
8287                     .withPreDhcpAction()
8288                     .withProvisioningTimeoutMs(PROVISIONING_TIMEOUT_FILS_CONNECTION_MS);
8289         } else {
8290             sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR);
8291             // We must clear the config BSSID, as the wifi chipset may decide to roam
8292             // from this point on and having the BSSID specified in the network block would
8293             // cause the roam to fail and the device to disconnect.
8294             clearTargetBssid("ObtainingIpAddress");
8295 
8296             // Stop IpClient in case we're switching from DHCP to static
8297             // configuration or vice versa.
8298             //
8299             // When we transition from static configuration to DHCP in
8300             // particular, we must tell ConnectivityService that we're
8301             // disconnected, because DHCP might take a long time during which
8302             // connectivity APIs such as getActiveNetworkInfo should not return
8303             // CONNECTED.
8304             stopDhcpSetup();
8305             setConfigurationsPriorToIpClientProvisioning(config);
8306 
8307             final Network network = (mNetworkAgent != null) ? mNetworkAgent.getNetwork() : null;
8308             prov.withNetwork(network);
8309             if (!isUsingStaticIp) {
8310                 ProvisioningConfiguration.ScanResultInfo scanResultInfo = null;
8311                 ScanResult scanResult = getScanResultInternal(config);
8312                 if (scanResult != null) {
8313                     final List<ScanResultInfo.InformationElement> ies =
8314                             new ArrayList<ScanResultInfo.InformationElement>();
8315                     for (ScanResult.InformationElement ie : scanResult.getInformationElements()) {
8316                         ScanResultInfo.InformationElement scanResultInfoIe =
8317                                 new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes());
8318                         ies.add(scanResultInfoIe);
8319                     }
8320                     scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID,
8321                             scanResult.BSSID, ies);
8322                 }
8323                 prov.withScanResultInfo(scanResultInfo)
8324                         .withPreDhcpAction();
8325             } else {
8326                 StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
8327                 prov.withStaticConfiguration(staticIpConfig)
8328                         .withoutIpReachabilityMonitor();
8329             }
8330         }
8331         if (mContext.getResources().getBoolean(
8332                 R.bool.config_wifiRemainConnectedAfterIpProvisionTimeout)) {
8333             prov.withProvisioningTimeoutMs(0);
8334         }
8335         mIpClient.startProvisioning(prov.build());
8336         return true;
8337     }
8338 
getOuiInternal(WifiConfiguration config)8339     private List<byte[]> getOuiInternal(WifiConfiguration config) {
8340         List<byte[]> ouis = new ArrayList<>();
8341         ScanResult scanResult = getScanResultInternal(config);
8342         if (scanResult == null) {
8343             return ouis;
8344         }
8345         List<InformationElementUtil.Vsa> vsas = InformationElementUtil.getVendorSpecificIE(
8346                 scanResult.informationElements);
8347         for (InformationElementUtil.Vsa vsa : vsas) {
8348             byte[] oui = vsa.oui;
8349             if (oui != null) {
8350                 ouis.add(oui);
8351             }
8352         }
8353         return ouis;
8354     }
8355 
getScanResultInternal(WifiConfiguration config)8356     private ScanResult getScanResultInternal(WifiConfiguration config) {
8357         ScanDetailCache scanDetailCache =
8358                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
8359         ScanResult scanResult = null;
8360         if (mLastBssid != null) {
8361             if (scanDetailCache != null) {
8362                 scanResult = scanDetailCache.getScanResult(mLastBssid);
8363             }
8364             // The cached scan result of connected network would be null at the first
8365             // connection, try to check full scan result list again to look up matched
8366             // scan result associated to the current BSSID.
8367             if (scanResult == null) {
8368                 scanResult = mScanRequestProxy.getScanResult(mLastBssid);
8369             }
8370         }
8371         return scanResult;
8372     }
8373 
8374     @Override
setWifiConnectedNetworkScorer(IBinder binder, IWifiConnectedNetworkScorer scorer, int callerUid)8375     public boolean setWifiConnectedNetworkScorer(IBinder binder,
8376             IWifiConnectedNetworkScorer scorer, int callerUid) {
8377         return mWifiScoreReport.setWifiConnectedNetworkScorer(binder, scorer, callerUid);
8378     }
8379 
8380     @Override
clearWifiConnectedNetworkScorer()8381     public void clearWifiConnectedNetworkScorer() {
8382         mWifiScoreReport.clearWifiConnectedNetworkScorer();
8383     }
8384 
8385     @Override
onNetworkSwitchAccepted(int targetNetworkId, String targetBssid)8386     public void onNetworkSwitchAccepted(int targetNetworkId, String targetBssid) {
8387         mWifiScoreReport.onNetworkSwitchAccepted(targetNetworkId, targetBssid);
8388     }
8389 
8390     @Override
onNetworkSwitchRejected(int targetNetworkId, String targetBssid)8391     public void onNetworkSwitchRejected(int targetNetworkId, String targetBssid) {
8392         mWifiScoreReport.onNetworkSwitchRejected(targetNetworkId, targetBssid);
8393     }
8394 
8395     @Override
sendMessageToClientModeImpl(Message msg)8396     public void sendMessageToClientModeImpl(Message msg) {
8397         sendMessage(msg);
8398     }
8399 
8400     @Override
getId()8401     public long getId() {
8402         return mId;
8403     }
8404 
8405     @Override
dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args)8406     public void dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args) {
8407         mWifiScoreReport.dump(fd, pw, args);
8408     }
8409 
8410     /**
8411      * Notifies changes in data connectivity of the default data SIM.
8412      */
8413     @Override
onCellularConnectivityChanged(@ifiDataStall.CellularDataStatusCode int status)8414     public void onCellularConnectivityChanged(@WifiDataStall.CellularDataStatusCode int status) {
8415         mWifiConfigManager.onCellularConnectivityChanged(status);
8416         // do a scan if no cell data and currently not connect to wifi
8417         if (status == WifiDataStall.CELLULAR_DATA_NOT_AVAILABLE
8418                 && getConnectedWifiConfigurationInternal() == null) {
8419             if (mContext.getResources().getBoolean(
8420                     R.bool.config_wifiScanOnCellularDataLossEnabled)) {
8421                 mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
8422             }
8423         }
8424     }
8425 
8426     @Override
setMboCellularDataStatus(boolean available)8427     public void setMboCellularDataStatus(boolean available) {
8428         mWifiNative.setMboCellularDataStatus(mInterfaceName, available);
8429     }
8430 
8431     @Override
getRoamingCapabilities()8432     public WifiNative.RoamingCapabilities getRoamingCapabilities() {
8433         return mWifiNative.getRoamingCapabilities(mInterfaceName);
8434     }
8435 
8436     @Override
configureRoaming(WifiNative.RoamingConfig config)8437     public boolean configureRoaming(WifiNative.RoamingConfig config) {
8438         return mWifiNative.configureRoaming(mInterfaceName, config);
8439     }
8440 
8441     @Override
enableRoaming(boolean enabled)8442     public boolean enableRoaming(boolean enabled) {
8443         int status = mWifiNative.enableFirmwareRoaming(
8444                 mInterfaceName, enabled
8445                         ? WifiNative.ENABLE_FIRMWARE_ROAMING
8446                         : WifiNative.DISABLE_FIRMWARE_ROAMING);
8447         return status == WifiNative.SET_FIRMWARE_ROAMING_SUCCESS;
8448     }
8449 
considerChangingFirmwareRoaming(boolean isIdle)8450     private void considerChangingFirmwareRoaming(boolean isIdle) {
8451         if (mClientModeManager.getRole() != ROLE_CLIENT_PRIMARY) {
8452             if (mVerboseLoggingEnabled) {
8453                 Log.v(TAG, "Idle mode changed: iface " + mInterfaceName + " is not primary.");
8454             }
8455             return;
8456         }
8457         if (!mWifiGlobals.isDisableFirmwareRoamingInIdleMode()
8458                 || !mWifiConnectivityHelper.isFirmwareRoamingSupported()) {
8459             // feature not enabled, or firmware roaming not supported - no need to continue.
8460             if (mVerboseLoggingEnabled) {
8461                 Log.v(TAG, "Idle mode changed: iface " + mInterfaceName
8462                         + " firmware roaming not supported");
8463             }
8464             return;
8465         }
8466         if (isIdle) {
8467             // disable firmware roaming if in idle mode
8468             if (mVerboseLoggingEnabled) {
8469                 Log.v(TAG, "Idle mode changed: iface " + mInterfaceName
8470                         + " disabling roaming");
8471             }
8472             enableRoaming(false);
8473             return;
8474         }
8475         // Exiting idle mode so re-enable firmware roaming, but only if the current use-case is
8476         // not the local-only use-case. The local-only use-case requires firmware roaming to be
8477         // always disabled.
8478         WifiConfiguration config = getConnectedWifiConfigurationInternal();
8479         if (config == null) {
8480             config = getConnectingWifiConfigurationInternal();
8481         }
8482         if (config != null && getClientRoleForMetrics(config)
8483                 == WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY) {
8484             return;
8485         }
8486         if (mVerboseLoggingEnabled) {
8487             Log.v(TAG, "Idle mode changed: iface " + mInterfaceName
8488                     + " enabling roaming");
8489         }
8490         mWifiInjector.getWifiRoamingModeManager().applyWifiRoamingMode(
8491                 mInterfaceName, mWifiInfo.getSSID());
8492     }
8493 
8494     @Override
onIdleModeChanged(boolean isIdle)8495     public void onIdleModeChanged(boolean isIdle) {
8496         considerChangingFirmwareRoaming(isIdle);
8497     }
8498 
8499     @Override
setCountryCode(String countryCode)8500     public boolean setCountryCode(String countryCode) {
8501         return mWifiNative.setStaCountryCode(mInterfaceName, countryCode);
8502     }
8503 
8504     @Override
getTxPktFates()8505     public List<TxFateReport> getTxPktFates() {
8506         return mWifiNative.getTxPktFates(mInterfaceName);
8507     }
8508 
8509     @Override
getRxPktFates()8510     public List<RxFateReport> getRxPktFates() {
8511         return mWifiNative.getRxPktFates(mInterfaceName);
8512     }
8513 
8514     @Override
setShouldReduceNetworkScore(boolean shouldReduceNetworkScore)8515     public void setShouldReduceNetworkScore(boolean shouldReduceNetworkScore) {
8516         mWifiScoreReport.setShouldReduceNetworkScore(shouldReduceNetworkScore);
8517     }
8518 
updateApfCapabilitiesOnRoleChangedToPrimary()8519     private void updateApfCapabilitiesOnRoleChangedToPrimary() {
8520         // If packet filter is supported on both connections, ignore since we would have already
8521         // specified the APF during the ipClient provisioning.
8522         if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)) {
8523             return;
8524         }
8525         if (mIpClient != null) {
8526             Log.i(TAG, "Role changed to primary - Update APF capabilities in IpClient");
8527             mIpClient.updateApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
8528         }
8529     }
8530 
8531     /**
8532      * Invoked by parent ConcreteClientModeManager whenever a role change occurs.
8533      */
onRoleChanged()8534     public void onRoleChanged() {
8535         ClientRole role = mClientModeManager.getRole();
8536         if (role == ROLE_CLIENT_PRIMARY) {
8537             updateApfCapabilitiesOnRoleChangedToPrimary();
8538             if (mScreenOn) {
8539                 // Start RSSI polling for the new primary network to enable scoring.
8540                 enableRssiPolling(true);
8541             }
8542         } else {
8543             if (mScreenOn && !isSecondaryInternet()) {
8544                 // Stop RSSI polling (if enabled) for the secondary network.
8545                 enableRssiPolling(false);
8546             }
8547         }
8548         WifiConfiguration connectedNetwork = getConnectedWifiConfiguration();
8549         if (connectedNetwork != null) {
8550             updateWifiInfoWhenConnected(connectedNetwork);
8551             // Update capabilities after a role change.
8552             updateCapabilities(connectedNetwork);
8553         }
8554         mWifiScoreReport.onRoleChanged(role);
8555     }
8556 
addPasspointInfoToLinkProperties(LinkProperties linkProperties)8557     private void addPasspointInfoToLinkProperties(LinkProperties linkProperties) {
8558         // CaptivePortalData.Builder.setVenueFriendlyName API not available on R
8559         if (!SdkLevel.isAtLeastS()) {
8560             return;
8561         }
8562         WifiConfiguration currentNetwork = getConnectedWifiConfigurationInternal();
8563         if (currentNetwork == null || !currentNetwork.isPasspoint()) {
8564             return;
8565         }
8566         ScanResult scanResult = mScanRequestProxy.getScanResult(mLastBssid);
8567 
8568         if (scanResult == null) {
8569             return;
8570         }
8571         URL venueUrl = mPasspointManager.getVenueUrl(scanResult);
8572 
8573         // Update the friendly name to populate the notification
8574         CaptivePortalData.Builder captivePortalDataBuilder = new CaptivePortalData.Builder()
8575                 .setVenueFriendlyName(currentNetwork.providerFriendlyName);
8576 
8577         // Update the Venue URL if available
8578         if (venueUrl != null) {
8579             captivePortalDataBuilder.setVenueInfoUrl(Uri.parse(venueUrl.toString()),
8580                     CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT);
8581         }
8582 
8583         // Update the T&C URL if available. The network is captive if T&C URL is available
8584         if (mTermsAndConditionsUrl != null) {
8585             captivePortalDataBuilder.setUserPortalUrl(
8586                     Uri.parse(mTermsAndConditionsUrl.toString()),
8587                     CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT).setCaptive(true);
8588         }
8589 
8590         linkProperties.setCaptivePortalData(captivePortalDataBuilder.build());
8591     }
8592 
8593     private boolean mHasQuit = false;
8594 
8595     @Override
onQuitting()8596     protected void onQuitting() {
8597         mHasQuit = true;
8598         mClientModeManager.onClientModeImplQuit();
8599     }
8600 
8601     /** Returns true if the ClientModeImpl has fully stopped, false otherwise. */
hasQuit()8602     public boolean hasQuit() {
8603         return mHasQuit;
8604     }
8605 
8606     /**
8607      * WifiVcnNetworkPolicyChangeListener tracks VCN-defined Network policies for a
8608      * WifiNetworkAgent. These policies are used to restart Networks or update their
8609      * NetworkCapabilities.
8610      */
8611     @SuppressLint("NewApi")
8612     private class WifiVcnNetworkPolicyChangeListener
8613             implements VcnManager.VcnNetworkPolicyChangeListener {
8614         @Override
onPolicyChanged()8615         public void onPolicyChanged() {
8616             if (mNetworkAgent == null) {
8617                 return;
8618             }
8619             // Update the NetworkAgent's NetworkCapabilities which will merge the current
8620             // capabilities with VcnManagementService's underlying Network policy.
8621             Log.i(getTag(), "VCN policy changed, updating NetworkCapabilities.");
8622             updateCapabilities();
8623         }
8624     }
8625 
8626     /**
8627      * Updates the default gateway mac address of the connected network config and updates the
8628      * linked networks resulting from the new default gateway.
8629      */
retrieveConnectedNetworkDefaultGateway()8630     private boolean retrieveConnectedNetworkDefaultGateway() {
8631         WifiConfiguration currentConfig = getConnectedWifiConfiguration();
8632         if (currentConfig == null) {
8633             logi("can't fetch config of current network id " + mLastNetworkId);
8634             return false;
8635         }
8636 
8637         // Find IPv4 default gateway.
8638         if (mLinkProperties == null) {
8639             logi("cannot retrieve default gateway from null link properties");
8640             return false;
8641         }
8642         String gatewayIPv4 = null;
8643         for (RouteInfo routeInfo : mLinkProperties.getRoutes()) {
8644             if (routeInfo.isDefaultRoute()
8645                     && routeInfo.getDestination().getAddress() instanceof Inet4Address
8646                     && routeInfo.hasGateway()) {
8647                 gatewayIPv4 = routeInfo.getGateway().getHostAddress();
8648                 break;
8649             }
8650         }
8651 
8652         if (TextUtils.isEmpty(gatewayIPv4)) {
8653             logi("default gateway ipv4 is null");
8654             return false;
8655         }
8656 
8657         String gatewayMac = macAddressFromRoute(gatewayIPv4);
8658         if (TextUtils.isEmpty(gatewayMac)) {
8659             logi("default gateway mac fetch failed for ipv4 addr = " + gatewayIPv4);
8660             return false;
8661         }
8662 
8663         if (mVerboseLoggingEnabled) {
8664             logi("Default Gateway MAC address of " + mLastBssid + " from routes is : "
8665                     + gatewayMac);
8666         }
8667         if (!mWifiConfigManager.setNetworkDefaultGwMacAddress(mLastNetworkId, gatewayMac)) {
8668             logi("default gateway mac set failed for " + currentConfig.getKey() + " network");
8669             return false;
8670         }
8671 
8672         return mWifiConfigManager.saveToStore();
8673     }
8674 
8675     /**
8676      * Links the supplied config to all matching saved configs and updates the WifiBlocklistMonitor
8677      * SSID allowlist with the linked networks.
8678      */
updateLinkedNetworks(@onNull WifiConfiguration config)8679     private void updateLinkedNetworks(@NonNull WifiConfiguration config) {
8680         if (!isPrimary()) {
8681             return;
8682         }
8683         if (!mContext.getResources().getBoolean(R.bool.config_wifiEnableLinkedNetworkRoaming)) {
8684             return;
8685         }
8686 
8687         SecurityParams params = mWifiNative.getCurrentNetworkSecurityParams(mInterfaceName);
8688         if (params == null) return;
8689 
8690         WifiConfiguration tmpConfigForCurrentSecurityParams = new WifiConfiguration();
8691         tmpConfigForCurrentSecurityParams.setSecurityParams(params);
8692         if (!WifiConfigurationUtil.isConfigLinkable(tmpConfigForCurrentSecurityParams)) return;
8693 
8694         // Don't set SSID allowlist if we're connected to a network with Fast BSS Transition.
8695         ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
8696                 config.networkId);
8697         if (scanDetailCache == null) {
8698             Log.i(TAG, "Do not update linked networks - no ScanDetailCache found for netId: "
8699                     + config.networkId);
8700             return;
8701         }
8702         ScanResult matchingScanResult = scanDetailCache.getScanResult(mLastBssid);
8703         if (matchingScanResult == null) {
8704             Log.i(TAG, "Do not update linked networks - no matching ScanResult found for BSSID: "
8705                     + mLastBssid);
8706             return;
8707         }
8708         String caps = matchingScanResult.capabilities;
8709         if (caps.contains("FT/PSK") || caps.contains("FT/SAE")) {
8710             Log.i(TAG, "Do not update linked networks - current connection is FT-PSK/FT-SAE");
8711             return;
8712         }
8713 
8714         mWifiConfigManager.updateLinkedNetworks(config.networkId);
8715         Map<String, WifiConfiguration> linkedNetworks = mWifiConfigManager
8716                 .getLinkedNetworksWithoutMasking(config.networkId);
8717 
8718         if (!mWifiNative.updateLinkedNetworks(mInterfaceName, config.networkId, linkedNetworks)) {
8719             return;
8720         }
8721         // Update internal configs once the connection requests are accepted.
8722         linkedNetworks.values().forEach(linkedConfig ->
8723                 mWifiConfigManager.setNetworkLastUsedSecurityParams(
8724                         linkedConfig.networkId, params));
8725 
8726         List<String> allowlistSsids = new ArrayList<>(linkedNetworks.values().stream()
8727                 .filter(linkedConfig -> linkedConfig.allowAutojoin)
8728                 .map(linkedConfig -> linkedConfig.SSID)
8729                 .collect(Collectors.toList()));
8730         if (allowlistSsids.size() > 0) {
8731             allowlistSsids.add(config.SSID);
8732         }
8733         mWifiBlocklistMonitor.setAllowlistSsids(config.SSID, allowlistSsids);
8734         mWifiBlocklistMonitor.updateFirmwareRoamingConfiguration(new ArraySet<>(allowlistSsids));
8735     }
8736 
checkAndHandleLinkedNetworkRoaming(String associatedBssid)8737     private boolean checkAndHandleLinkedNetworkRoaming(String associatedBssid) {
8738         if (!mContext.getResources().getBoolean(R.bool.config_wifiEnableLinkedNetworkRoaming)) {
8739             return false;
8740         }
8741 
8742         ScanResult scanResult = mScanRequestProxy.getScanResult(associatedBssid);
8743         if (scanResult == null) {
8744             return false;
8745         }
8746 
8747         WifiConfiguration config = mWifiConfigManager
8748                 .getSavedNetworkForScanResult(scanResult);
8749         if (config == null || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
8750                 || mLastNetworkId == config.networkId) {
8751             return false;
8752         }
8753 
8754         mIsLinkedNetworkRoaming = true;
8755         setTargetBssid(config, associatedBssid);
8756         mTargetNetworkId = config.networkId;
8757         mTargetWifiConfiguration = config;
8758         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
8759         sendNetworkChangeBroadcast(DetailedState.CONNECTING);
8760         mWifiInfo.setFrequency(scanResult.frequency);
8761         mWifiInfo.setBSSID(associatedBssid);
8762         updateCurrentConnectionInfo();
8763         return true;
8764     }
8765 
8766     @RequiresApi(Build.VERSION_CODES.S)
8767     private @WifiConfiguration.RecentFailureReason int
mboAssocDisallowedReasonCodeToWifiConfigurationRecentFailureReason( @boOceConstants.MboAssocDisallowedReasonCode int reasonCode)8768             mboAssocDisallowedReasonCodeToWifiConfigurationRecentFailureReason(
8769             @MboOceConstants.MboAssocDisallowedReasonCode int reasonCode) {
8770         switch (reasonCode) {
8771             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_MAX_NUM_STA_ASSOCIATED:
8772                 return WifiConfiguration.RECENT_FAILURE_MBO_ASSOC_DISALLOWED_MAX_NUM_STA_ASSOCIATED;
8773             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_AIR_INTERFACE_OVERLOADED:
8774                 return WifiConfiguration
8775                         .RECENT_FAILURE_MBO_ASSOC_DISALLOWED_AIR_INTERFACE_OVERLOADED;
8776             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_AUTH_SERVER_OVERLOADED:
8777                 return WifiConfiguration.RECENT_FAILURE_MBO_ASSOC_DISALLOWED_AUTH_SERVER_OVERLOADED;
8778             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_INSUFFICIENT_RSSI:
8779                 return WifiConfiguration.RECENT_FAILURE_MBO_ASSOC_DISALLOWED_INSUFFICIENT_RSSI;
8780             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_UNSPECIFIED:
8781             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_RESERVED_0:
8782             case MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_RESERVED:
8783             default:
8784                 return WifiConfiguration.RECENT_FAILURE_MBO_ASSOC_DISALLOWED_UNSPECIFIED;
8785         }
8786     }
8787 
8788     /**
8789      * To set association rejection status in wifi config.
8790      * @param netId The network ID.
8791      * @param assocRejectEventInfo Association rejection information.
8792      */
setAssociationRejectionStatusInConfig(int netId, AssocRejectEventInfo assocRejectEventInfo)8793     private void setAssociationRejectionStatusInConfig(int netId,
8794             AssocRejectEventInfo assocRejectEventInfo) {
8795         int statusCode = assocRejectEventInfo.statusCode;
8796         @WifiConfiguration.RecentFailureReason int reason;
8797 
8798         switch (statusCode) {
8799             case StaIfaceStatusCode.AP_UNABLE_TO_HANDLE_NEW_STA:
8800                 reason = WifiConfiguration.RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA;
8801                 break;
8802             case StaIfaceStatusCode.ASSOC_REJECTED_TEMPORARILY:
8803                 reason = WifiConfiguration.RECENT_FAILURE_REFUSED_TEMPORARILY;
8804                 break;
8805             case StaIfaceStatusCode.DENIED_POOR_CHANNEL_CONDITIONS:
8806                 reason = WifiConfiguration.RECENT_FAILURE_POOR_CHANNEL_CONDITIONS;
8807                 break;
8808             default:
8809                 // do nothing
8810                 return;
8811         }
8812 
8813         if (SdkLevel.isAtLeastS()) {
8814             if (assocRejectEventInfo.mboAssocDisallowedInfo != null) {
8815                 reason = mboAssocDisallowedReasonCodeToWifiConfigurationRecentFailureReason(
8816                         assocRejectEventInfo.mboAssocDisallowedInfo.mReasonCode);
8817             } else if (assocRejectEventInfo.oceRssiBasedAssocRejectInfo != null) {
8818                 reason = WifiConfiguration.RECENT_FAILURE_OCE_RSSI_BASED_ASSOCIATION_REJECTION;
8819             }
8820         }
8821 
8822         mWifiConfigManager.setRecentFailureAssociationStatus(netId, reason);
8823 
8824     }
8825 
checkIfNeedDisconnectSecondaryWifi()8826     private void checkIfNeedDisconnectSecondaryWifi() {
8827         if (!isPrimary()) {
8828             return;
8829         }
8830         if (isConnected()) {
8831             ConcreteClientModeManager ccmm =
8832                     mWifiInjector.getActiveModeWarden().getClientModeManagerInRole(
8833                             ROLE_CLIENT_SECONDARY_LONG_LIVED);
8834             if (ccmm != null && ccmm.isConnected() && ccmm.isSecondaryInternet()) {
8835                 WifiInfo secondaryWifiInfo = ccmm.getConnectionInfo();
8836                 if (secondaryWifiInfo == null) return;
8837                 if ((secondaryWifiInfo.is5GHz() && mWifiInfo.is5GHz())
8838                         || (secondaryWifiInfo.is6GHz() && mWifiInfo.is6GHz())
8839                         || (secondaryWifiInfo.is24GHz() && mWifiInfo.is24GHz())) {
8840                     if (mVerboseLoggingEnabled) {
8841                         Log.d(TAG, "The master wifi and secondary wifi are at the same band,"
8842                                 + " disconnect the secondary wifi");
8843                     }
8844                     ccmm.disconnect();
8845                 }
8846             }
8847         }
8848     }
8849 
setSelectedRcoiForPasspoint(WifiConfiguration config)8850     private void setSelectedRcoiForPasspoint(WifiConfiguration config) {
8851         // Only relevant for Passpoint providers with roaming consortium subscriptions
8852         if (config.isPasspoint() && config.roamingConsortiumIds != null
8853                 && config.roamingConsortiumIds.length > 0) {
8854             long selectedRcoi = mPasspointManager.getSelectedRcoiForNetwork(
8855                     config.getPasspointUniqueId(), config.SSID);
8856             if (selectedRcoi != 0) {
8857                 config.enterpriseConfig.setSelectedRcoi(selectedRcoi);
8858             }
8859         }
8860     }
8861 
updateCurrentConnectionInfo()8862     private void updateCurrentConnectionInfo() {
8863         if (isPrimary()) {
8864             mWifiInjector.getActiveModeWarden().updateCurrentConnectionInfo();
8865         }
8866     }
8867 }
8868