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