1 /* 2 * Copyright (C) 2008 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 android.net.wifi.SupplicantState; 20 import android.net.wifi.WifiEnterpriseConfig; 21 import android.net.wifi.WifiManager; 22 import android.net.wifi.WifiSsid; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.util.ArraySet; 26 import android.util.Log; 27 import android.util.SparseArray; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.util.Protocol; 31 import com.android.server.wifi.MboOceController.BtmFrameData; 32 import com.android.server.wifi.WifiCarrierInfoManager.SimAuthRequestData; 33 import com.android.server.wifi.hotspot2.AnqpEvent; 34 import com.android.server.wifi.hotspot2.IconEvent; 35 import com.android.server.wifi.hotspot2.WnmData; 36 37 import java.util.HashMap; 38 import java.util.Map; 39 import java.util.Set; 40 41 /** 42 * Listen for events from the wpa_supplicant & wificond and broadcast them on 43 * to the various {@link ClientModeImpl} modules interested in handling these events. 44 * @hide 45 */ 46 public class WifiMonitor { 47 private static final String TAG = "WifiMonitor"; 48 49 /* Supplicant events reported to a state machine */ 50 private static final int BASE = Protocol.BASE_WIFI_MONITOR; 51 52 /* Connection to supplicant established */ 53 public static final int SUP_CONNECTION_EVENT = BASE + 1; 54 /* Connection to supplicant lost */ 55 public static final int SUP_DISCONNECTION_EVENT = BASE + 2; 56 /* Network connection completed */ 57 public static final int NETWORK_CONNECTION_EVENT = BASE + 3; 58 /* Network disconnection completed */ 59 public static final int NETWORK_DISCONNECTION_EVENT = BASE + 4; 60 /* Scan results are available */ 61 public static final int SCAN_RESULTS_EVENT = BASE + 5; 62 /* Supplicate state changed */ 63 public static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 6; 64 /* Password failure and EAP authentication failure */ 65 public static final int AUTHENTICATION_FAILURE_EVENT = BASE + 7; 66 /* WPS success detected */ 67 public static final int WPS_SUCCESS_EVENT = BASE + 8; 68 /* WPS failure detected */ 69 public static final int WPS_FAIL_EVENT = BASE + 9; 70 /* WPS overlap detected */ 71 public static final int WPS_OVERLAP_EVENT = BASE + 10; 72 /* WPS timeout detected */ 73 public static final int WPS_TIMEOUT_EVENT = BASE + 11; 74 75 /* Request Identity */ 76 public static final int SUP_REQUEST_IDENTITY = BASE + 15; 77 78 /* Request SIM Auth */ 79 public static final int SUP_REQUEST_SIM_AUTH = BASE + 16; 80 81 public static final int SCAN_FAILED_EVENT = BASE + 17; 82 /* Pno scan results are available */ 83 public static final int PNO_SCAN_RESULTS_EVENT = BASE + 18; 84 85 86 /* Indicates assoc reject event */ 87 public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43; 88 public static final int ANQP_DONE_EVENT = BASE + 44; 89 public static final int ASSOCIATED_BSSID_EVENT = BASE + 45; 90 public static final int TARGET_BSSID_EVENT = BASE + 46; 91 92 /* hotspot 2.0 ANQP events */ 93 public static final int GAS_QUERY_START_EVENT = BASE + 51; 94 public static final int GAS_QUERY_DONE_EVENT = BASE + 52; 95 public static final int RX_HS20_ANQP_ICON_EVENT = BASE + 53; 96 97 /* hotspot 2.0 events */ 98 public static final int HS20_REMEDIATION_EVENT = BASE + 61; 99 100 /* MBO/OCE events */ 101 public static final int MBO_OCE_BSS_TM_HANDLING_DONE = BASE + 71; 102 103 /* Fils network connection completed */ 104 public static final int FILS_NETWORK_CONNECTION_EVENT = BASE + 62; 105 106 /* WPS config errrors */ 107 private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12; 108 private static final int CONFIG_AUTH_FAILURE = 18; 109 110 /* WPS error indications */ 111 private static final int REASON_TKIP_ONLY_PROHIBITED = 1; 112 private static final int REASON_WEP_PROHIBITED = 2; 113 114 private final WifiInjector mWifiInjector; 115 private boolean mVerboseLoggingEnabled = false; 116 private boolean mConnected = false; 117 WifiMonitor(WifiInjector wifiInjector)118 public WifiMonitor(WifiInjector wifiInjector) { 119 mWifiInjector = wifiInjector; 120 } 121 enableVerboseLogging(int verbose)122 void enableVerboseLogging(int verbose) { 123 if (verbose > 0) { 124 mVerboseLoggingEnabled = true; 125 } else { 126 mVerboseLoggingEnabled = false; 127 } 128 } 129 130 private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>(); registerHandler(String iface, int what, Handler handler)131 public synchronized void registerHandler(String iface, int what, Handler handler) { 132 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 133 if (ifaceHandlers == null) { 134 ifaceHandlers = new SparseArray<>(); 135 mHandlerMap.put(iface, ifaceHandlers); 136 } 137 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what); 138 if (ifaceWhatHandlers == null) { 139 ifaceWhatHandlers = new ArraySet<>(); 140 ifaceHandlers.put(what, ifaceWhatHandlers); 141 } 142 ifaceWhatHandlers.add(handler); 143 } 144 145 /** 146 * Deregister the given |handler| 147 * @param iface 148 * @param what 149 * @param handler 150 */ deregisterHandler(String iface, int what, Handler handler)151 public synchronized void deregisterHandler(String iface, int what, Handler handler) { 152 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 153 if (ifaceHandlers == null) { 154 return; 155 } 156 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what); 157 if (ifaceWhatHandlers == null) { 158 return; 159 } 160 ifaceWhatHandlers.remove(handler); 161 } 162 163 private final Map<String, Boolean> mMonitoringMap = new HashMap<>(); isMonitoring(String iface)164 private boolean isMonitoring(String iface) { 165 Boolean val = mMonitoringMap.get(iface); 166 if (val == null) { 167 return false; 168 } else { 169 return val.booleanValue(); 170 } 171 } 172 173 /** 174 * Enable/Disable monitoring for the provided iface. 175 * 176 * @param iface Name of the iface. 177 * @param enabled true to enable, false to disable. 178 */ 179 @VisibleForTesting setMonitoring(String iface, boolean enabled)180 public void setMonitoring(String iface, boolean enabled) { 181 mMonitoringMap.put(iface, enabled); 182 } 183 setMonitoringNone()184 private void setMonitoringNone() { 185 for (String iface : mMonitoringMap.keySet()) { 186 setMonitoring(iface, false); 187 } 188 } 189 190 /** 191 * Start Monitoring for wpa_supplicant events. 192 * 193 * @param iface Name of iface. 194 */ startMonitoring(String iface)195 public synchronized void startMonitoring(String iface) { 196 if (mVerboseLoggingEnabled) Log.d(TAG, "startMonitoring(" + iface + ")"); 197 setMonitoring(iface, true); 198 broadcastSupplicantConnectionEvent(iface); 199 } 200 201 /** 202 * Stop Monitoring for wpa_supplicant events. 203 * 204 * @param iface Name of iface. 205 */ stopMonitoring(String iface)206 public synchronized void stopMonitoring(String iface) { 207 if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")"); 208 setMonitoring(iface, true); 209 broadcastSupplicantDisconnectionEvent(iface); 210 setMonitoring(iface, false); 211 } 212 213 /** 214 * Stop Monitoring for wpa_supplicant events. 215 * 216 * TODO: Add unit tests for these once we remove the legacy code. 217 */ stopAllMonitoring()218 public synchronized void stopAllMonitoring() { 219 mConnected = false; 220 setMonitoringNone(); 221 } 222 223 224 /** 225 * Similar functions to Handler#sendMessage that send the message to the registered handler 226 * for the given interface and message what. 227 * All of these should be called with the WifiMonitor class lock 228 */ sendMessage(String iface, int what)229 private void sendMessage(String iface, int what) { 230 sendMessage(iface, Message.obtain(null, what)); 231 } 232 sendMessage(String iface, int what, Object obj)233 private void sendMessage(String iface, int what, Object obj) { 234 sendMessage(iface, Message.obtain(null, what, obj)); 235 } 236 sendMessage(String iface, int what, int arg1)237 private void sendMessage(String iface, int what, int arg1) { 238 sendMessage(iface, Message.obtain(null, what, arg1, 0)); 239 } 240 sendMessage(String iface, int what, int arg1, int arg2)241 private void sendMessage(String iface, int what, int arg1, int arg2) { 242 sendMessage(iface, Message.obtain(null, what, arg1, arg2)); 243 } 244 sendMessage(String iface, int what, int arg1, int arg2, Object obj)245 private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) { 246 sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj)); 247 } 248 sendMessage(String iface, Message message)249 private void sendMessage(String iface, Message message) { 250 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 251 if (iface != null && ifaceHandlers != null) { 252 if (isMonitoring(iface)) { 253 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what); 254 if (ifaceWhatHandlers != null) { 255 for (Handler handler : ifaceWhatHandlers) { 256 if (handler != null) { 257 sendMessage(handler, Message.obtain(message)); 258 } 259 } 260 } 261 } else { 262 if (mVerboseLoggingEnabled) { 263 Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); 264 } 265 } 266 } else { 267 if (mVerboseLoggingEnabled) { 268 Log.d(TAG, "Sending to all monitors because there's no matching iface"); 269 } 270 for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) { 271 if (isMonitoring(entry.getKey())) { 272 Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what); 273 for (Handler handler : ifaceWhatHandlers) { 274 if (handler != null) { 275 sendMessage(handler, Message.obtain(message)); 276 } 277 } 278 } 279 } 280 } 281 282 message.recycle(); 283 } 284 sendMessage(Handler handler, Message message)285 private void sendMessage(Handler handler, Message message) { 286 message.setTarget(handler); 287 message.sendToTarget(); 288 } 289 290 /** 291 * Broadcast the WPS fail event to all the handlers registered for this event. 292 * 293 * @param iface Name of iface on which this occurred. 294 * @param cfgError Configuration error code. 295 * @param vendorErrorCode Vendor specific error indication code. 296 */ broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode)297 public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) { 298 int reason = 0; 299 switch(vendorErrorCode) { 300 case REASON_TKIP_ONLY_PROHIBITED: 301 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED); 302 return; 303 case REASON_WEP_PROHIBITED: 304 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED); 305 return; 306 default: 307 reason = vendorErrorCode; 308 break; 309 } 310 switch(cfgError) { 311 case CONFIG_AUTH_FAILURE: 312 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE); 313 return; 314 case CONFIG_MULTIPLE_PBC_DETECTED: 315 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR); 316 return; 317 default: 318 if (reason == 0) { 319 reason = cfgError; 320 } 321 break; 322 } 323 //For all other errors, return a generic internal error 324 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason); 325 } 326 327 /** 328 * Broadcast the WPS succes event to all the handlers registered for this event. 329 * 330 * @param iface Name of iface on which this occurred. 331 */ broadcastWpsSuccessEvent(String iface)332 public void broadcastWpsSuccessEvent(String iface) { 333 sendMessage(iface, WPS_SUCCESS_EVENT); 334 } 335 336 /** 337 * Broadcast the WPS overlap event to all the handlers registered for this event. 338 * 339 * @param iface Name of iface on which this occurred. 340 */ broadcastWpsOverlapEvent(String iface)341 public void broadcastWpsOverlapEvent(String iface) { 342 sendMessage(iface, WPS_OVERLAP_EVENT); 343 } 344 345 /** 346 * Broadcast the WPS timeout event to all the handlers registered for this event. 347 * 348 * @param iface Name of iface on which this occurred. 349 */ broadcastWpsTimeoutEvent(String iface)350 public void broadcastWpsTimeoutEvent(String iface) { 351 sendMessage(iface, WPS_TIMEOUT_EVENT); 352 } 353 354 /** 355 * Broadcast the ANQP done event to all the handlers registered for this event. 356 * 357 * @param iface Name of iface on which this occurred. 358 * @param anqpEvent ANQP result retrieved. 359 */ broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent)360 public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) { 361 sendMessage(iface, ANQP_DONE_EVENT, anqpEvent); 362 } 363 364 /** 365 * Broadcast the Icon done event to all the handlers registered for this event. 366 * 367 * @param iface Name of iface on which this occurred. 368 * @param iconEvent Instance of IconEvent containing the icon data retrieved. 369 */ broadcastIconDoneEvent(String iface, IconEvent iconEvent)370 public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) { 371 sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent); 372 } 373 374 /** 375 * Broadcast the WNM event to all the handlers registered for this event. 376 * 377 * @param iface Name of iface on which this occurred. 378 * @param wnmData Instance of WnmData containing the event data. 379 */ broadcastWnmEvent(String iface, WnmData wnmData)380 public void broadcastWnmEvent(String iface, WnmData wnmData) { 381 sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData); 382 } 383 384 /** 385 * Broadcast the Network identity request event to all the handlers registered for this event. 386 * 387 * @param iface Name of iface on which this occurred. 388 * @param networkId ID of the network in wpa_supplicant. 389 * @param ssid SSID of the network. 390 */ broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid)391 public void broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid) { 392 sendMessage(iface, SUP_REQUEST_IDENTITY, 0, networkId, ssid); 393 } 394 395 /** 396 * Broadcast the Network Gsm Sim auth request event to all the handlers registered for this 397 * event. 398 * 399 * @param iface Name of iface on which this occurred. 400 * @param networkId ID of the network in wpa_supplicant. 401 * @param ssid SSID of the network. 402 * @param data Accompanying event data. 403 */ broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid, String[] data)404 public void broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid, 405 String[] data) { 406 sendMessage(iface, SUP_REQUEST_SIM_AUTH, 407 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.SIM, ssid, data)); 408 } 409 410 /** 411 * Broadcast the Network Umts Sim auth request event to all the handlers registered for this 412 * event. 413 * 414 * @param iface Name of iface on which this occurred. 415 * @param networkId ID of the network in wpa_supplicant. 416 * @param ssid SSID of the network. 417 * @param data Accompanying event data. 418 */ broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid, String[] data)419 public void broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid, 420 String[] data) { 421 sendMessage(iface, SUP_REQUEST_SIM_AUTH, 422 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.AKA, ssid, data)); 423 } 424 425 /** 426 * Broadcast scan result event to all the handlers registered for this event. 427 * @param iface Name of iface on which this occurred. 428 */ broadcastScanResultEvent(String iface)429 public void broadcastScanResultEvent(String iface) { 430 sendMessage(iface, SCAN_RESULTS_EVENT); 431 } 432 433 /** 434 * Broadcast pno scan result event to all the handlers registered for this event. 435 * @param iface Name of iface on which this occurred. 436 */ broadcastPnoScanResultEvent(String iface)437 public void broadcastPnoScanResultEvent(String iface) { 438 sendMessage(iface, PNO_SCAN_RESULTS_EVENT); 439 } 440 441 /** 442 * Broadcast scan failed event to all the handlers registered for this event. 443 * @param iface Name of iface on which this occurred. 444 */ broadcastScanFailedEvent(String iface)445 public void broadcastScanFailedEvent(String iface) { 446 sendMessage(iface, SCAN_FAILED_EVENT); 447 } 448 449 /** 450 * Broadcast the authentication failure event to all the handlers registered for this event. 451 * 452 * @param iface Name of iface on which this occurred. 453 * @param reason Reason for authentication failure. This has to be one of the 454 * {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_NONE}, 455 * {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_TIMEOUT}, 456 * {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_WRONG_PSWD}, 457 * {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_EAP_FAILURE} 458 * @param errorCode Error code associated with the authentication failure event. 459 * A value of -1 is used when no error code is reported. 460 */ broadcastAuthenticationFailureEvent(String iface, int reason, int errorCode)461 public void broadcastAuthenticationFailureEvent(String iface, int reason, int errorCode) { 462 sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, reason, errorCode); 463 } 464 465 /** 466 * Broadcast the association rejection event to all the handlers registered for this event. 467 * 468 * @param iface Name of iface on which this occurred. 469 * @param status Status code for association rejection. 470 * @param timedOut Indicates if the association timed out. 471 * @param bssid BSSID of the access point from which we received the reject. 472 */ broadcastAssociationRejectionEvent(String iface, int status, boolean timedOut, String bssid)473 public void broadcastAssociationRejectionEvent(String iface, int status, boolean timedOut, 474 String bssid) { 475 sendMessage(iface, ASSOCIATION_REJECTION_EVENT, timedOut ? 1 : 0, status, bssid); 476 } 477 478 /** 479 * Broadcast the association success event to all the handlers registered for this event. 480 * 481 * @param iface Name of iface on which this occurred. 482 * @param bssid BSSID of the access point. 483 */ broadcastAssociatedBssidEvent(String iface, String bssid)484 public void broadcastAssociatedBssidEvent(String iface, String bssid) { 485 sendMessage(iface, ASSOCIATED_BSSID_EVENT, 0, 0, bssid); 486 } 487 488 /** 489 * Broadcast the start of association event to all the handlers registered for this event. 490 * 491 * @param iface Name of iface on which this occurred. 492 * @param bssid BSSID of the access point. 493 */ broadcastTargetBssidEvent(String iface, String bssid)494 public void broadcastTargetBssidEvent(String iface, String bssid) { 495 sendMessage(iface, TARGET_BSSID_EVENT, 0, 0, bssid); 496 } 497 498 /** 499 * Broadcast the network connection event to all the handlers registered for this event. 500 * 501 * @param iface Name of iface on which this occurred. 502 * @param networkId ID of the network in wpa_supplicant. 503 * @param bssid BSSID of the access point. 504 */ broadcastNetworkConnectionEvent(String iface, int networkId, String bssid)505 public void broadcastNetworkConnectionEvent(String iface, int networkId, String bssid) { 506 sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, 0, bssid); 507 } 508 509 /** 510 * Broadcast the fils network connection event to all the handlers registered for this event. 511 * 512 * @param iface Name of iface on which this occurred. 513 * @param networkId ID of the network in wpa_supplicant. 514 * @param bssid BSSID of the access point. 515 */ broadcastFilsNetworkConnectionEvent(String iface, int networkId, String bssid)516 public void broadcastFilsNetworkConnectionEvent(String iface, int networkId, String bssid) { 517 sendMessage(iface, FILS_NETWORK_CONNECTION_EVENT, networkId, 0, bssid); 518 } 519 520 /** 521 * Broadcast the network disconnection event to all the handlers registered for this event. 522 * 523 * @param iface Name of iface on which this occurred. 524 * @param local Whether the disconnect was locally triggered. 525 * @param reason Disconnect reason code. 526 * @param bssid BSSID of the access point. 527 */ broadcastNetworkDisconnectionEvent(String iface, int local, int reason, String bssid)528 public void broadcastNetworkDisconnectionEvent(String iface, int local, int reason, 529 String bssid) { 530 sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, bssid); 531 } 532 533 /** 534 * Broadcast the supplicant state change event to all the handlers registered for this event. 535 * 536 * @param iface Name of iface on which this occurred. 537 * @param networkId ID of the network in wpa_supplicant. 538 * @param bssid BSSID of the access point. 539 * @param newSupplicantState New supplicant state. 540 */ broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid, String bssid, SupplicantState newSupplicantState)541 public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid, 542 String bssid, 543 SupplicantState newSupplicantState) { 544 sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 545 new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState)); 546 } 547 548 /** 549 * Broadcast the connection to wpa_supplicant event to all the handlers registered for 550 * this event. 551 * 552 * @param iface Name of iface on which this occurred. 553 */ broadcastSupplicantConnectionEvent(String iface)554 public void broadcastSupplicantConnectionEvent(String iface) { 555 sendMessage(iface, SUP_CONNECTION_EVENT); 556 } 557 558 /** 559 * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for 560 * this event. 561 * 562 * @param iface Name of iface on which this occurred. 563 */ broadcastSupplicantDisconnectionEvent(String iface)564 public void broadcastSupplicantDisconnectionEvent(String iface) { 565 sendMessage(iface, SUP_DISCONNECTION_EVENT); 566 } 567 568 /** 569 * Broadcast the bss transition management frame handling event 570 * to all the handlers registered for this event. 571 * 572 * @param iface Name of iface on which this occurred. 573 */ broadcastBssTmHandlingDoneEvent(String iface, BtmFrameData btmFrmData)574 public void broadcastBssTmHandlingDoneEvent(String iface, BtmFrameData btmFrmData) { 575 sendMessage(iface, MBO_OCE_BSS_TM_HANDLING_DONE, btmFrmData); 576 } 577 } 578