1 // 2 // Copyright (C) 2013 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 // This file provides tests to verify that Callback80211Metrics sends UMA 18 // notifications for appropriate messages and doesn't send them for 19 // inappropriate messages. 20 21 #include "shill/wifi/callback80211_metrics.h" 22 23 #include <memory> 24 25 #include <gmock/gmock.h> 26 #include <gtest/gtest.h> 27 28 #include "shill/mock_event_dispatcher.h" 29 #include "shill/mock_log.h" 30 #include "shill/mock_metrics.h" 31 #include "shill/net/ieee80211.h" 32 #include "shill/net/netlink_packet.h" 33 #include "shill/net/nl80211_message.h" 34 #include "shill/refptr_types.h" 35 36 using base::Bind; 37 using std::unique_ptr; 38 using testing::_; 39 using testing::Test; 40 41 namespace shill { 42 43 namespace { 44 45 // Unless otherwise specified, these data blocks have been collected by shill 46 // using NetlinkManager while, simultaneously (and manually) comparing shill 47 // output with that of the 'iw' code from which it was derived. The test 48 // strings represent the raw packet data coming from the kernel. The 49 // comments above each of these strings is the markup that 'iw' outputs for 50 // each of these packets. 51 52 // These constants are consistent across the applicable packets, below. 53 54 const uint16_t kNl80211FamilyId = 0x13; 55 const IEEE_80211::WiFiReasonCode kExpectedDisconnectReason = 56 IEEE_80211::kReasonCodePreviousAuthenticationInvalid; 57 58 // NL80211_CMD_DISCONNECT message. 59 // wlan0 (phy #0): disconnected (by AP) reason: 2: Previous authentication no 60 // longer valid 61 62 const unsigned char kDisconnectMessage[] = { 63 0x30, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x30, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 66 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 67 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x36, 0x00, 68 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x47, 0x00, 69 }; 70 71 // NL80211_CMD_DISCONNECT message. 72 // Copied from kDisconnectMessage but with most of the payload removed. 73 74 const unsigned char kEmptyDisconnectMessage[] = { 75 0x1c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x30, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 78 0x00, 0x00, 0x00, 0x00, 79 }; 80 81 // NL80211_CMD_DEAUTHENTICATE message. 82 // wlan0 (phy #0): deauth c0:3f:0e:77:e8:7f -> ff:ff:ff:ff:ff:ff reason 2: 83 // Previous authentication no longer valid [frame: c0 00 00 00 ff ff ff ff 84 // ff ff c0 3f 0e 77 e8 7f c0 3f 0e 77 e8 7f c0 0e 02 00] 85 86 const unsigned char kDeauthenticateMessage[] = { 87 0x44, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 0x27, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 90 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 91 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x33, 0x00, 92 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 93 0xff, 0xff, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 94 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0xc0, 0x0e, 95 0x02, 0x00, 0x00, 0x00, 96 }; 97 98 // NL80211_CMD_DEAUTHENTICATE message. 99 // Copied from kDeauthenticateMessage but with most of the payload 100 // removed. 101 102 const unsigned char kEmptyDeauthenticateMessage[] = { 103 0x1c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 0x27, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 106 0x00, 0x00, 0x00, 0x00, 107 }; 108 109 // NL80211_CMD_NEW_STATION message. 110 // kNewStationMessage is an nl80211 message that's not a deauthenticate or 111 // disconnect message. Used to make sure that only those nl80211 messages 112 // generate an UMA message. 113 // wlan0: new station c0:3f:0e:77:e8:7f 114 115 const unsigned char kNewStationMessage[] = { 116 0x34, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 118 0x13, 0x01, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 119 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00, 120 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00, 121 0x08, 0x00, 0x2e, 0x00, 0x13, 0x01, 0x00, 0x00, 122 0x04, 0x00, 0x15, 0x00, 123 }; 124 125 // CTRL_CMD_GETFAMILY message. 126 // kGetFamilyMessage is not an nl80211 message. Used to make sure that 127 // non-nl80211 messages don't generate an UMA message. 128 // 129 // Extracted from net.log. It's just a non-nl80211 message (it's actually a 130 // message that's sent to the kernel rather than one received from the kernel 131 // but the code doesn't differentiate and this message was much shorter than the 132 // response). 133 134 const unsigned char kGetFamilyMessage[] = { 135 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 136 0x6e, 0x6c, 0x38, 0x30, 0x32, 0x31, 0x31, 0x00 137 }; 138 139 } // namespace 140 141 class Callback80211MetricsTest : public Test { 142 public: 143 Callback80211MetricsTest() : 144 metrics_(&dispatcher_), callback_(&metrics_) { 145 message_factory_.AddFactoryMethod( 146 kNl80211FamilyId, Bind(&Nl80211Message::CreateMessage)); 147 Nl80211Message::SetMessageType(kNl80211FamilyId); 148 } 149 150 protected: 151 MockEventDispatcher dispatcher_; 152 MockMetrics metrics_; 153 NetlinkMessageFactory message_factory_; 154 Callback80211Metrics callback_; 155 }; 156 157 // Make sure that notifications happen for correctly formed messages. 158 TEST_F(Callback80211MetricsTest, DisconnectMessage) { 159 NetlinkPacket packet(kDisconnectMessage, sizeof(kDisconnectMessage)); 160 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 161 &packet, NetlinkMessage::MessageContext())); 162 EXPECT_CALL(metrics_, Notify80211Disconnect(Metrics::kDisconnectedByAp, 163 kExpectedDisconnectReason)); 164 callback_.CollectDisconnectStatistics(*netlink_message); 165 } 166 167 TEST_F(Callback80211MetricsTest, DeauthMessage) { 168 NetlinkPacket packet(kDeauthenticateMessage, sizeof(kDeauthenticateMessage)); 169 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 170 &packet, NetlinkMessage::MessageContext())); 171 EXPECT_CALL(metrics_, Notify80211Disconnect(Metrics::kDisconnectedNotByAp, 172 kExpectedDisconnectReason)); 173 callback_.CollectDisconnectStatistics(*netlink_message); 174 } 175 176 // Make sure there's no notification if there's no reason code in the message. 177 TEST_F(Callback80211MetricsTest, EmptyDisconnectMessage) { 178 NetlinkPacket packet( 179 kEmptyDisconnectMessage, sizeof(kEmptyDisconnectMessage)); 180 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 181 &packet, NetlinkMessage::MessageContext())); 182 EXPECT_CALL(metrics_, Notify80211Disconnect(_, _)).Times(0); 183 callback_.CollectDisconnectStatistics(*netlink_message); 184 } 185 186 TEST_F(Callback80211MetricsTest, EmptyDeauthMessage) { 187 NetlinkPacket packet( 188 kEmptyDeauthenticateMessage, sizeof(kEmptyDeauthenticateMessage)); 189 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 190 &packet, NetlinkMessage::MessageContext())); 191 EXPECT_CALL(metrics_, Notify80211Disconnect(_, _)).Times(0); 192 callback_.CollectDisconnectStatistics(*netlink_message); 193 } 194 195 // Make sure the callback doesn't notify anyone for message of the wrong type. 196 TEST_F(Callback80211MetricsTest, Nl80211NotDisconnectDeauthMessage) { 197 NetlinkPacket packet(kNewStationMessage, sizeof(kNewStationMessage)); 198 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 199 &packet, NetlinkMessage::MessageContext())); 200 EXPECT_CALL(metrics_, Notify80211Disconnect(_, _)).Times(0); 201 callback_.CollectDisconnectStatistics(*netlink_message); 202 } 203 204 TEST_F(Callback80211MetricsTest, NotNl80211Message) { 205 NetlinkPacket packet(kGetFamilyMessage, sizeof(kGetFamilyMessage)); 206 unique_ptr<NetlinkMessage> netlink_message(message_factory_.CreateMessage( 207 &packet, NetlinkMessage::MessageContext())); 208 EXPECT_CALL(metrics_, Notify80211Disconnect(_, _)).Times(0); 209 callback_.CollectDisconnectStatistics(*netlink_message); 210 } 211 212 } // namespace shill 213