Home | History | Annotate | Download | only in wifi
      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