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