blob: 50aa0bb15668bbba71a4ffac005fc96d726b6055 [file] [log] [blame]
Paul Stewartac802ac2013-04-02 15:45:24 -07001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/eap_listener.h"
6
7#include <linux/if_ether.h>
8#include <linux/if_packet.h>
9#include <netinet/in.h>
10
Paul Stewartac802ac2013-04-02 15:45:24 -070011#include <base/bind.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070012#include <base/compiler_specific.h>
Paul Stewartac802ac2013-04-02 15:45:24 -070013
14#include "shill/eap_protocol.h"
15#include "shill/event_dispatcher.h"
16#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070017#include "shill/net/sockets.h"
Paul Stewartac802ac2013-04-02 15:45:24 -070018
19namespace shill {
20
21const size_t EapListener::kMaxEapPacketLength =
22 sizeof(eap_protocol::Ieee8021xHdr) + sizeof(eap_protocol::EapHeader);
23
Paul Stewarta794cd62015-06-16 13:13:10 -070024EapListener::EapListener(EventDispatcher* event_dispatcher,
Paul Stewartac802ac2013-04-02 15:45:24 -070025 int interface_index)
26 : dispatcher_(event_dispatcher),
27 interface_index_(interface_index),
28 sockets_(new Sockets()),
29 socket_(-1) {}
30
31EapListener::~EapListener() {}
32
33bool EapListener::Start() {
34 if (!CreateSocket()) {
35 LOG(ERROR) << "Could not open EAP listener socket.";
36 Stop();
37 return false;
38 }
39
40 receive_request_handler_.reset(
41 dispatcher_->CreateReadyHandler(
42 socket_,
43 IOHandler::kModeInput,
44 base::Bind(&EapListener::ReceiveRequest, base::Unretained(this))));
45
46 return true;
47}
48
49void EapListener::Stop() {
50 receive_request_handler_.reset();
51 socket_closer_.reset();
52 socket_ = -1;
53}
54
55
56bool EapListener::CreateSocket() {
57 int socket = sockets_->Socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
58 if (socket == -1) {
59 PLOG(ERROR) << "Could not create EAP listener socket";
60 return false;
61 }
62 socket_ = socket;
63 socket_closer_.reset(new ScopedSocketCloser(sockets_.get(), socket_));
64
65 if (sockets_->SetNonBlocking(socket_) != 0) {
66 PLOG(ERROR) << "Could not set socket to be non-blocking";
67 return false;
68 }
69
70 sockaddr_ll socket_address;
71 memset(&socket_address, 0, sizeof(socket_address));
72 socket_address.sll_family = AF_PACKET;
73 socket_address.sll_protocol = htons(ETH_P_PAE);
74 socket_address.sll_ifindex = interface_index_;
75
76 if (sockets_->Bind(socket_,
Paul Stewarta794cd62015-06-16 13:13:10 -070077 reinterpret_cast<struct sockaddr*>(&socket_address),
Paul Stewartac802ac2013-04-02 15:45:24 -070078 sizeof(socket_address)) != 0) {
79 PLOG(ERROR) << "Could not bind socket to interface";
80 return false;
81 }
82
83 return true;
84}
85
86void EapListener::ReceiveRequest(int fd) {
87 struct ALIGNAS(1) {
88 eap_protocol::Ieee8021xHdr onex_header;
89 eap_protocol::EapHeader eap_header;
90 } payload;
91 sockaddr_ll remote_address;
92 memset(&remote_address, 0, sizeof(remote_address));
93 socklen_t socklen = sizeof(remote_address);
94 int result = sockets_->RecvFrom(
95 socket_, &payload, sizeof(payload), 0,
Paul Stewarta794cd62015-06-16 13:13:10 -070096 reinterpret_cast<struct sockaddr*>(&remote_address),
Paul Stewartac802ac2013-04-02 15:45:24 -070097 &socklen);
98 if (result < 0) {
99 PLOG(ERROR) << "Socket recvfrom failed";
100 Stop();
101 return;
102 }
103
104 if (result != sizeof(payload)) {
105 LOG(INFO) << "Short EAP packet received";
106 return;
107 }
108
Paul Stewart475ce5a2014-05-08 10:06:41 -0700109 if (payload.onex_header.version < eap_protocol::kIeee8021xEapolVersion1 ||
Paul Stewartac802ac2013-04-02 15:45:24 -0700110 payload.onex_header.type != eap_protocol::kIIeee8021xTypeEapPacket ||
111 payload.eap_header.code != eap_protocol::kEapCodeRequest) {
112 LOG(INFO) << "Packet is not a valid EAP request";
113 return;
114 }
115
116 request_received_callback_.Run();
117}
118
119} // namespace shill