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