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:
Callback80211MetricsTest()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.
TEST_F(Callback80211MetricsTest,DisconnectMessage)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
TEST_F(Callback80211MetricsTest,DeauthMessage)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.
TEST_F(Callback80211MetricsTest,EmptyDisconnectMessage)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
TEST_F(Callback80211MetricsTest,EmptyDeauthMessage)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.
TEST_F(Callback80211MetricsTest,Nl80211NotDisconnectDeauthMessage)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
TEST_F(Callback80211MetricsTest,NotNl80211Message)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