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