Home | History | Annotate | Download | only in shill
      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 #include "shill/eap_listener.h"
     18 
     19 #include <linux/if_ether.h>
     20 #include <linux/if_packet.h>
     21 #include <netinet/in.h>
     22 #include <string.h>
     23 
     24 #include <algorithm>
     25 
     26 #include <base/bind.h>
     27 #include <gtest/gtest.h>
     28 
     29 #include "shill/eap_protocol.h"
     30 #include "shill/mock_event_dispatcher.h"
     31 #include "shill/mock_log.h"
     32 #include "shill/net/byte_string.h"
     33 #include "shill/net/mock_sockets.h"
     34 
     35 using testing::_;
     36 using testing::HasSubstr;
     37 using testing::Invoke;
     38 using testing::Return;
     39 using testing::StrictMock;
     40 
     41 namespace shill {
     42 
     43 class EapListenerTest : public testing::Test {
     44  public:
     45   EapListenerTest() : listener_(&dispatcher_, kInterfaceIndex) {}
     46   virtual ~EapListenerTest() {}
     47 
     48   virtual void SetUp() {
     49     sockets_ = new StrictMock<MockSockets>();
     50     // Passes ownership.
     51     listener_.sockets_.reset(sockets_);
     52     listener_.set_request_received_callback(
     53         base::Bind(&EapListenerTest::ReceiveCallback, base::Unretained(this)));
     54   }
     55 
     56   virtual void TearDown() {
     57     if (GetSocket() == kSocketFD) {
     58       EXPECT_CALL(*sockets_, Close(kSocketFD));
     59       listener_.Stop();
     60     }
     61   }
     62 
     63   ssize_t SimulateRecvFrom(int sockfd, void* buf, size_t len, int flags,
     64                            struct sockaddr* src_addr, socklen_t* addrlen);
     65 
     66   MOCK_METHOD0(ReceiveCallback, void());
     67 
     68  protected:
     69   static const int kInterfaceIndex;
     70   static const int kSocketFD;
     71   static const uint8_t kEapPacketPayload[];
     72 
     73   bool CreateSocket() { return listener_.CreateSocket(); }
     74   int GetInterfaceIndex() { return listener_.interface_index_; }
     75   size_t GetMaxEapPacketLength() { return EapListener::kMaxEapPacketLength; }
     76   int GetSocket() { return listener_.socket_; }
     77   void StartListener() { StartListenerWithFD(kSocketFD); }
     78   void ReceiveRequest() { listener_.ReceiveRequest(kSocketFD); }
     79   void StartListenerWithFD(int fd);
     80 
     81   MockEventDispatcher dispatcher_;
     82   EapListener listener_;
     83 
     84   // Owned by EapListener, and tracked here only for mocks.
     85   MockSockets* sockets_;
     86 
     87   // Tests can assign this in order to set the data isreturned in our
     88   // mock implementation of Sockets::RecvFrom().
     89   ByteString recvfrom_reply_data_;
     90 };
     91 
     92 // static
     93 const int EapListenerTest::kInterfaceIndex = 123;
     94 const int EapListenerTest::kSocketFD = 456;
     95 const uint8_t EapListenerTest::kEapPacketPayload[] = {
     96   eap_protocol::kIeee8021xEapolVersion2,
     97   eap_protocol::kIIeee8021xTypeEapPacket,
     98   0x00, 0x00,  // Payload length (should be 5, but unparsed by EapListener).
     99   eap_protocol::kEapCodeRequest,
    100   0x00,        // Identifier (unparsed).
    101   0x00, 0x00,  // Packet length (should be 5, but unparsed by EapListener).
    102   0x01         // Request type: Identity (not parsed by EapListener).
    103 };
    104 
    105 ssize_t EapListenerTest::SimulateRecvFrom(int sockfd, void* buf, size_t len,
    106                                           int flags, struct sockaddr* src_addr,
    107                                           socklen_t* addrlen) {
    108   // Mimic behavior of the real recvfrom -- copy no more than requested.
    109   int copy_length = std::min(recvfrom_reply_data_.GetLength(), len);
    110   memcpy(buf, recvfrom_reply_data_.GetConstData(), copy_length);
    111   return copy_length;
    112 }
    113 
    114 MATCHER_P(IsEapLinkAddress, interface_index, "") {
    115   const struct sockaddr_ll* socket_address =
    116       reinterpret_cast<const struct sockaddr_ll*>(arg);
    117   return socket_address->sll_family == AF_PACKET &&
    118       socket_address->sll_protocol == htons(ETH_P_PAE) &&
    119       socket_address->sll_ifindex == interface_index;
    120 }
    121 
    122 void EapListenerTest::StartListenerWithFD(int fd) {
    123   EXPECT_CALL(*sockets_, Socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)))
    124       .WillOnce(Return(fd));
    125   EXPECT_CALL(*sockets_, SetNonBlocking(fd)).WillOnce(Return(0));
    126   EXPECT_CALL(*sockets_,
    127               Bind(fd, IsEapLinkAddress(kInterfaceIndex), sizeof(sockaddr_ll)))
    128       .WillOnce(Return(0));
    129   EXPECT_CALL(dispatcher_, CreateReadyHandler(fd, IOHandler::kModeInput, _));
    130   EXPECT_TRUE(listener_.Start());
    131   EXPECT_EQ(fd, listener_.socket_);
    132 }
    133 
    134 TEST_F(EapListenerTest, Constructor) {
    135   EXPECT_EQ(kInterfaceIndex, GetInterfaceIndex());
    136   EXPECT_EQ(8, GetMaxEapPacketLength());
    137   EXPECT_EQ(-1, GetSocket());
    138 }
    139 
    140 TEST_F(EapListenerTest, SocketOpenFail) {
    141   ScopedMockLog log;
    142   EXPECT_CALL(log,
    143       Log(logging::LOG_ERROR, _,
    144           HasSubstr("Could not create EAP listener socket"))).Times(1);
    145 
    146   EXPECT_CALL(*sockets_, Socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)))
    147       .WillOnce(Return(-1));
    148   EXPECT_FALSE(CreateSocket());
    149 }
    150 
    151 TEST_F(EapListenerTest, SocketNonBlockingFail) {
    152   ScopedMockLog log;
    153   EXPECT_CALL(log,
    154       Log(logging::LOG_ERROR, _,
    155           HasSubstr("Could not set socket to be non-blocking"))).Times(1);
    156 
    157   EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
    158   EXPECT_CALL(*sockets_, SetNonBlocking(kSocketFD)).WillOnce(Return(-1));
    159   EXPECT_FALSE(CreateSocket());
    160 }
    161 
    162 TEST_F(EapListenerTest, SocketBindFail) {
    163   ScopedMockLog log;
    164   EXPECT_CALL(log,
    165       Log(logging::LOG_ERROR, _,
    166           HasSubstr("Could not bind socket to interface"))).Times(1);
    167 
    168   EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
    169   EXPECT_CALL(*sockets_, SetNonBlocking(kSocketFD)).WillOnce(Return(0));
    170   EXPECT_CALL(*sockets_, Bind(kSocketFD, _, _)).WillOnce(Return(-1));
    171   EXPECT_FALSE(CreateSocket());
    172 }
    173 
    174 TEST_F(EapListenerTest, StartSuccess) {
    175   StartListener();
    176 }
    177 
    178 TEST_F(EapListenerTest, StartMultipleTimes) {
    179   const int kFirstSocketFD = kSocketFD + 1;
    180   StartListenerWithFD(kFirstSocketFD);
    181   EXPECT_CALL(*sockets_, Close(kFirstSocketFD));
    182   StartListener();
    183 }
    184 
    185 TEST_F(EapListenerTest, Stop) {
    186   StartListener();
    187   EXPECT_EQ(kSocketFD, GetSocket());
    188   EXPECT_CALL(*sockets_, Close(kSocketFD));
    189   listener_.Stop();
    190   EXPECT_EQ(-1, GetSocket());
    191 }
    192 
    193 
    194 TEST_F(EapListenerTest, ReceiveFail) {
    195   StartListener();
    196   EXPECT_CALL(*sockets_,
    197               RecvFrom(kSocketFD, _, GetMaxEapPacketLength(), 0, _, _))
    198       .WillOnce(Return(-1));
    199   EXPECT_CALL(*this, ReceiveCallback()).Times(0);
    200   EXPECT_CALL(*sockets_, Close(kSocketFD));
    201 
    202   ScopedMockLog log;
    203   // RecvFrom returns an error.
    204   EXPECT_CALL(log,
    205       Log(logging::LOG_ERROR, _,
    206           HasSubstr("Socket recvfrom failed"))).Times(1);
    207   ReceiveRequest();
    208 }
    209 
    210 TEST_F(EapListenerTest, ReceiveEmpty) {
    211   StartListener();
    212   EXPECT_CALL(*sockets_,
    213               RecvFrom(kSocketFD, _, GetMaxEapPacketLength(), 0, _, _))
    214       .WillOnce(Return(0));
    215   EXPECT_CALL(*this, ReceiveCallback()).Times(0);
    216   ReceiveRequest();
    217 }
    218 
    219 TEST_F(EapListenerTest, ReceiveShort) {
    220   StartListener();
    221   recvfrom_reply_data_ = ByteString(kEapPacketPayload,
    222                                     GetMaxEapPacketLength() - 1);
    223   EXPECT_CALL(*sockets_,
    224               RecvFrom(kSocketFD, _, GetMaxEapPacketLength(), 0, _, _))
    225       .WillOnce(Invoke(this, &EapListenerTest::SimulateRecvFrom));
    226   EXPECT_CALL(*this, ReceiveCallback()).Times(0);
    227   ScopedMockLog log;
    228   EXPECT_CALL(log,
    229       Log(logging::LOG_INFO, _,
    230           HasSubstr("Short EAP packet received"))).Times(1);
    231   ReceiveRequest();
    232 }
    233 
    234 TEST_F(EapListenerTest, ReceiveInvalid) {
    235   StartListener();
    236   // We're partially initializing this field, just making sure at least one
    237   // part of it is incorrect.
    238   uint8_t bad_payload[sizeof(kEapPacketPayload)] = {
    239     eap_protocol::kIeee8021xEapolVersion1 - 1
    240   };
    241   recvfrom_reply_data_ = ByteString(bad_payload, sizeof(bad_payload));
    242   EXPECT_CALL(*sockets_,
    243               RecvFrom(kSocketFD, _, GetMaxEapPacketLength(), 0, _, _))
    244       .WillOnce(Invoke(this, &EapListenerTest::SimulateRecvFrom));
    245   EXPECT_CALL(*this, ReceiveCallback()).Times(0);
    246   ScopedMockLog log;
    247   EXPECT_CALL(log,
    248       Log(logging::LOG_INFO, _,
    249           HasSubstr("Packet is not a valid EAP request"))).Times(1);
    250   ReceiveRequest();
    251 }
    252 
    253 TEST_F(EapListenerTest, ReceiveSuccess) {
    254   StartListener();
    255   recvfrom_reply_data_ =
    256       ByteString(kEapPacketPayload, sizeof(kEapPacketPayload));
    257   EXPECT_CALL(*sockets_,
    258               RecvFrom(kSocketFD, _, GetMaxEapPacketLength(), 0, _, _))
    259       .WillOnce(Invoke(this, &EapListenerTest::SimulateRecvFrom));
    260   EXPECT_CALL(*this, ReceiveCallback()).Times(1);
    261   ReceiveRequest();
    262 }
    263 
    264 }  // namespace shill
    265