1 // 2 // Copyright (C) 2012 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 #include "shill/wifi/callback80211_metrics.h" 18 19 #include <string> 20 21 #include "shill/logging.h" 22 #include "shill/metrics.h" 23 #include "shill/net/ieee80211.h" 24 #include "shill/net/netlink_manager.h" 25 #include "shill/net/nl80211_message.h" 26 27 using std::string; 28 29 namespace shill { 30 31 namespace Logging { 32 static auto kModuleLogScope = ScopeLogger::kWiFi; 33 static string ObjectID(const Callback80211Metrics* c) { 34 return "(callback80211metrics)"; 35 } 36 } 37 38 Callback80211Metrics::Callback80211Metrics(Metrics* metrics) 39 : metrics_(metrics) {} 40 41 IEEE_80211::WiFiReasonCode Callback80211Metrics::WiFiReasonCodeFromUint16( 42 uint16_t reason) const { 43 IEEE_80211::WiFiReasonCode reason_enum = IEEE_80211::kReasonCodeInvalid; 44 if (reason == IEEE_80211::kReasonCodeReserved0 || 45 reason == IEEE_80211::kReasonCodeReserved12 || 46 (reason >= IEEE_80211::kReasonCodeReservedBegin25 && 47 reason <= IEEE_80211::kReasonCodeReservedEnd31) || 48 (reason >= IEEE_80211::kReasonCodeReservedBegin40 && 49 reason <= IEEE_80211::kReasonCodeReservedEnd44) || 50 reason >= IEEE_80211::kReasonCodeMax) { 51 SLOG(this, 1) << "Invalid reason code in disconnect message"; 52 reason_enum = IEEE_80211::kReasonCodeInvalid; 53 } else { 54 reason_enum = static_cast<IEEE_80211::WiFiReasonCode>(reason); 55 } 56 return reason_enum; 57 } 58 59 void Callback80211Metrics::CollectDisconnectStatistics( 60 const NetlinkMessage& netlink_message) { 61 if (!metrics_) { 62 return; 63 } 64 // We only handle disconnect and deauthenticate messages, both of which are 65 // nl80211 messages. 66 if (netlink_message.message_type() != Nl80211Message::GetMessageType()) { 67 return; 68 } 69 const Nl80211Message& message = 70 * reinterpret_cast<const Nl80211Message*>(&netlink_message); 71 72 // Station-instigated disconnects provide their information in the 73 // deauthenticate message but AP-instigated disconnects provide it in the 74 // disconnect message. 75 uint16_t reason = IEEE_80211::kReasonCodeUnspecified; 76 if (message.command() == DeauthenticateMessage::kCommand) { 77 SLOG(this, 3) << "Handling Deauthenticate Message"; 78 message.Print(3, 3); 79 // If there's no frame, this is probably an AP-caused disconnect and 80 // there'll be a disconnect message to tell us about that. 81 ByteString rawdata; 82 if (!message.const_attributes()->GetRawAttributeValue(NL80211_ATTR_FRAME, 83 &rawdata)) { 84 SLOG(this, 5) << "No frame in deauthenticate message, ignoring"; 85 return; 86 } 87 Nl80211Frame frame(rawdata); 88 reason = frame.reason(); 89 } else if (message.command() == DisconnectMessage::kCommand) { 90 SLOG(this, 3) << "Handling Disconnect Message"; 91 message.Print(3, 3); 92 // If there's no reason code, this is probably a STA-caused disconnect and 93 // there was be a disconnect message to tell us about that. 94 if (!message.const_attributes()->GetU16AttributeValue( 95 NL80211_ATTR_REASON_CODE, &reason)) { 96 SLOG(this, 5) << "No reason code in disconnect message, ignoring"; 97 return; 98 } 99 } else { 100 return; 101 } 102 103 IEEE_80211::WiFiReasonCode reason_enum = WiFiReasonCodeFromUint16(reason); 104 105 Metrics::WiFiDisconnectByWhom by_whom = 106 message.const_attributes()->IsFlagAttributeTrue( 107 NL80211_ATTR_DISCONNECTED_BY_AP) ? Metrics::kDisconnectedByAp : 108 Metrics::kDisconnectedNotByAp; 109 SLOG(this, 1) << "Notify80211Disconnect by " << (by_whom ? "station" : "AP") 110 << " because:" << reason_enum; 111 metrics_->Notify80211Disconnect(by_whom, reason_enum); 112 } 113 114 } // namespace shill. 115