• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
EapListenerTest()45   EapListenerTest() : listener_(&dispatcher_, kInterfaceIndex) {}
~EapListenerTest()46   virtual ~EapListenerTest() {}
47 
SetUp()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 
TearDown()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 
CreateSocket()73   bool CreateSocket() { return listener_.CreateSocket(); }
GetInterfaceIndex()74   int GetInterfaceIndex() { return listener_.interface_index_; }
GetMaxEapPacketLength()75   size_t GetMaxEapPacketLength() { return EapListener::kMaxEapPacketLength; }
GetSocket()76   int GetSocket() { return listener_.socket_; }
StartListener()77   void StartListener() { StartListenerWithFD(kSocketFD); }
ReceiveRequest()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 
SimulateRecvFrom(int sockfd,void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)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 
StartListenerWithFD(int fd)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 
TEST_F(EapListenerTest,Constructor)134 TEST_F(EapListenerTest, Constructor) {
135   EXPECT_EQ(kInterfaceIndex, GetInterfaceIndex());
136   EXPECT_EQ(8, GetMaxEapPacketLength());
137   EXPECT_EQ(-1, GetSocket());
138 }
139 
TEST_F(EapListenerTest,SocketOpenFail)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 
TEST_F(EapListenerTest,SocketNonBlockingFail)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 
TEST_F(EapListenerTest,SocketBindFail)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 
TEST_F(EapListenerTest,StartSuccess)174 TEST_F(EapListenerTest, StartSuccess) {
175   StartListener();
176 }
177 
TEST_F(EapListenerTest,StartMultipleTimes)178 TEST_F(EapListenerTest, StartMultipleTimes) {
179   const int kFirstSocketFD = kSocketFD + 1;
180   StartListenerWithFD(kFirstSocketFD);
181   EXPECT_CALL(*sockets_, Close(kFirstSocketFD));
182   StartListener();
183 }
184 
TEST_F(EapListenerTest,Stop)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 
TEST_F(EapListenerTest,ReceiveFail)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 
TEST_F(EapListenerTest,ReceiveEmpty)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 
TEST_F(EapListenerTest,ReceiveShort)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 
TEST_F(EapListenerTest,ReceiveInvalid)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 
TEST_F(EapListenerTest,ReceiveSuccess)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