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 23 #include <base/bind.h> 24 #include <base/compiler_specific.h> 25 26 #include "shill/eap_protocol.h" 27 #include "shill/event_dispatcher.h" 28 #include "shill/logging.h" 29 #include "shill/net/sockets.h" 30 31 namespace shill { 32 33 const size_t EapListener::kMaxEapPacketLength = 34 sizeof(eap_protocol::Ieee8021xHdr) + sizeof(eap_protocol::EapHeader); 35 36 EapListener::EapListener(EventDispatcher* event_dispatcher, 37 int interface_index) 38 : dispatcher_(event_dispatcher), 39 interface_index_(interface_index), 40 sockets_(new Sockets()), 41 socket_(-1) {} 42 43 EapListener::~EapListener() {} 44 45 bool EapListener::Start() { 46 if (!CreateSocket()) { 47 LOG(ERROR) << "Could not open EAP listener socket."; 48 Stop(); 49 return false; 50 } 51 52 receive_request_handler_.reset( 53 dispatcher_->CreateReadyHandler( 54 socket_, 55 IOHandler::kModeInput, 56 base::Bind(&EapListener::ReceiveRequest, base::Unretained(this)))); 57 58 return true; 59 } 60 61 void EapListener::Stop() { 62 receive_request_handler_.reset(); 63 socket_closer_.reset(); 64 socket_ = -1; 65 } 66 67 68 bool EapListener::CreateSocket() { 69 int socket = sockets_->Socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); 70 if (socket == -1) { 71 PLOG(ERROR) << "Could not create EAP listener socket"; 72 return false; 73 } 74 socket_ = socket; 75 socket_closer_.reset(new ScopedSocketCloser(sockets_.get(), socket_)); 76 77 if (sockets_->SetNonBlocking(socket_) != 0) { 78 PLOG(ERROR) << "Could not set socket to be non-blocking"; 79 return false; 80 } 81 82 sockaddr_ll socket_address; 83 memset(&socket_address, 0, sizeof(socket_address)); 84 socket_address.sll_family = AF_PACKET; 85 socket_address.sll_protocol = htons(ETH_P_PAE); 86 socket_address.sll_ifindex = interface_index_; 87 88 if (sockets_->Bind(socket_, 89 reinterpret_cast<struct sockaddr*>(&socket_address), 90 sizeof(socket_address)) != 0) { 91 PLOG(ERROR) << "Could not bind socket to interface"; 92 return false; 93 } 94 95 return true; 96 } 97 98 void EapListener::ReceiveRequest(int fd) { 99 struct ALIGNAS(1) { 100 eap_protocol::Ieee8021xHdr onex_header; 101 eap_protocol::EapHeader eap_header; 102 } payload; 103 sockaddr_ll remote_address; 104 memset(&remote_address, 0, sizeof(remote_address)); 105 socklen_t socklen = sizeof(remote_address); 106 int result = sockets_->RecvFrom( 107 socket_, &payload, sizeof(payload), 0, 108 reinterpret_cast<struct sockaddr*>(&remote_address), 109 &socklen); 110 if (result < 0) { 111 PLOG(ERROR) << "Socket recvfrom failed"; 112 Stop(); 113 return; 114 } 115 116 if (result != sizeof(payload)) { 117 LOG(INFO) << "Short EAP packet received"; 118 return; 119 } 120 121 if (payload.onex_header.version < eap_protocol::kIeee8021xEapolVersion1 || 122 payload.onex_header.type != eap_protocol::kIIeee8021xTypeEapPacket || 123 payload.eap_header.code != eap_protocol::kEapCodeRequest) { 124 LOG(INFO) << "Packet is not a valid EAP request"; 125 return; 126 } 127 128 request_received_callback_.Run(); 129 } 130 131 } // namespace shill 132