1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2013 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
16ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
17ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include "shill/eap_listener.h"
18ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
19ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include <linux/if_ether.h>
20ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include <linux/if_packet.h>
21ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include <netinet/in.h>
22ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
23ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include <base/bind.h>
24a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko#include <base/compiler_specific.h>
25ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
26ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include "shill/eap_protocol.h"
27ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include "shill/event_dispatcher.h"
28ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart#include "shill/logging.h"
298d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/sockets.h"
30ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
31ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartnamespace shill {
32ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
33ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartconst size_t EapListener::kMaxEapPacketLength =
34ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    sizeof(eap_protocol::Ieee8021xHdr) + sizeof(eap_protocol::EapHeader);
35ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
36a794cd60a7339d576ea2eed263a4f0a20fb255afPaul StewartEapListener::EapListener(EventDispatcher* event_dispatcher,
37ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart                         int interface_index)
38ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    : dispatcher_(event_dispatcher),
39ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      interface_index_(interface_index),
40ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      sockets_(new Sockets()),
41ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      socket_(-1) {}
42ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
43ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul StewartEapListener::~EapListener() {}
44ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
45ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartbool EapListener::Start() {
46ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (!CreateSocket()) {
47ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    LOG(ERROR) << "Could not open EAP listener socket.";
48ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    Stop();
49ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return false;
50ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
51ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
52ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  receive_request_handler_.reset(
53ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    dispatcher_->CreateReadyHandler(
54ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart        socket_,
55ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart        IOHandler::kModeInput,
56ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart        base::Bind(&EapListener::ReceiveRequest, base::Unretained(this))));
57ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
58ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  return true;
59ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart}
60ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
61ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartvoid EapListener::Stop() {
62ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  receive_request_handler_.reset();
63ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_closer_.reset();
64ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_ = -1;
65ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart}
66ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
67ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
68ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartbool EapListener::CreateSocket() {
69ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  int socket = sockets_->Socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
70ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (socket == -1) {
71ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    PLOG(ERROR) << "Could not create EAP listener socket";
72ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return false;
73ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
74ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_ = socket;
75ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_closer_.reset(new ScopedSocketCloser(sockets_.get(), socket_));
76ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
77ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (sockets_->SetNonBlocking(socket_) != 0) {
78ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    PLOG(ERROR) << "Could not set socket to be non-blocking";
79ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return false;
80ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
81ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
82ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  sockaddr_ll socket_address;
83ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  memset(&socket_address, 0, sizeof(socket_address));
84ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_address.sll_family = AF_PACKET;
85ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_address.sll_protocol = htons(ETH_P_PAE);
86ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socket_address.sll_ifindex = interface_index_;
87ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
88ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (sockets_->Bind(socket_,
89a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                     reinterpret_cast<struct sockaddr*>(&socket_address),
90ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart                     sizeof(socket_address)) != 0) {
91ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    PLOG(ERROR) << "Could not bind socket to interface";
92ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return false;
93ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
94ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
95ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  return true;
96ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart}
97ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
98ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewartvoid EapListener::ReceiveRequest(int fd) {
99ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  struct ALIGNAS(1) {
100ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    eap_protocol::Ieee8021xHdr onex_header;
101ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    eap_protocol::EapHeader eap_header;
102ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  } payload;
103ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  sockaddr_ll remote_address;
104ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  memset(&remote_address, 0, sizeof(remote_address));
105ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  socklen_t socklen = sizeof(remote_address);
106ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  int result = sockets_->RecvFrom(
107ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      socket_, &payload, sizeof(payload), 0,
108a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart      reinterpret_cast<struct sockaddr*>(&remote_address),
109ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      &socklen);
110ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (result < 0) {
111ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    PLOG(ERROR) << "Socket recvfrom failed";
112ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    Stop();
113ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return;
114ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
115ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
116ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  if (result != sizeof(payload)) {
117ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    LOG(INFO) << "Short EAP packet received";
118ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return;
119ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
120ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
121475ce5aad3c7c4b1f53783d969bc904ed5f1c065Paul Stewart  if (payload.onex_header.version < eap_protocol::kIeee8021xEapolVersion1 ||
122ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      payload.onex_header.type != eap_protocol::kIIeee8021xTypeEapPacket ||
123ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart      payload.eap_header.code != eap_protocol::kEapCodeRequest) {
124ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    LOG(INFO) << "Packet is not a valid EAP request";
125ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart    return;
126ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  }
127ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
128ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart  request_received_callback_.Run();
129ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart}
130ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart
131ac802ac47b09e93cd61ae67e10ab5feecee1cf15Paul Stewart}  // namespace shill
132