1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 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// 1691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 1791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart#include "shill/arp_packet.h" 1891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 1991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart#include <net/ethernet.h> 2091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart#include <net/if_arp.h> 2191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart#include <netinet/in.h> 2291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart#include <string.h> 2391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 243a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko#include <limits> 253a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko 26b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h" 2791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 2891a5aac3d03883be7d652096b1c018298096edcdPaul Stewartnamespace shill { 2991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 30ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewartconst size_t ArpPacket::kMinPayloadSize = ETH_ZLEN - ETH_HLEN; 31ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewart 3291a5aac3d03883be7d652096b1c018298096edcdPaul StewartArpPacket::ArpPacket() 33417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart : operation_(0), 34417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart local_ip_address_(IPAddress::kFamilyUnknown), 3591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_ip_address_(IPAddress::kFamilyUnknown) {} 3691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 3791a5aac3d03883be7d652096b1c018298096edcdPaul StewartArpPacket::ArpPacket( 38a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart const IPAddress& local_ip, const IPAddress& remote_ip, 39a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart const ByteString& local_mac, const ByteString& remote_mac) 4091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart : local_ip_address_(local_ip), 4191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_ip_address_(remote_ip), 4291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart local_mac_address_(local_mac), 4391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_mac_address_(remote_mac) {} 4491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 4591a5aac3d03883be7d652096b1c018298096edcdPaul StewartArpPacket::~ArpPacket() {} 4691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 4791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// Format of an ARP packet (all multi-byte values are big-endian): 4891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// 4991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// Byte 0 Byte 1 Byte 2 Byte 3 5091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------+-----------------+-----------------+-----------------+ 5191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Format of hardware address (ether)| Format of Protocol Address (IP) | 5291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------+-----------------+-----------------------------------+ 5391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Hardware Length | Protocol Length | ARP Protocol OpCode | 5491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------+-----------------+-----------------------------------+ 5591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// 5691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// plus a variable length section... 5791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// 5891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------------------------------------------------------------+ 5991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Sender Hardware Address (of length "Hardware Length")... | 6091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------------------------------------------------------------+ 6191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Sender IP Address (of length "Protocol Length")... | 6291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------------------------------------------------------------+ 6391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Target Hardware Address (of length "Hardware Length")... | 6491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------------------------------------------------------------+ 6591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// | Target IP Address (of length "Protocol Length")... | 6691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// +-----------------------------------------------------------------------+ 67a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool ArpPacket::Parse(const ByteString& packet) { 6891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart arphdr header; 6991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (packet.GetLength() < sizeof(header)) { 7091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Packet size " << packet.GetLength() 7191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << " is too short to contain ARP header."; 7291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 7391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 7491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 7591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart memcpy(&header, packet.GetConstData(), sizeof(header)); 7691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 777fab89734d88724a288e96a9996b15548c5294c7Ben Chan const uint16_t hardware_type = ntohs(header.ar_hrd); 7891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (hardware_type != ARPHRD_ETHER) { 7991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart NOTIMPLEMENTED() << "Packet is of unknown ARPHRD type " 8091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << hardware_type; 8191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 8291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 837fab89734d88724a288e96a9996b15548c5294c7Ben Chan const uint16_t protocol = ntohs(header.ar_pro); 8491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart IPAddress::Family family = IPAddress::kFamilyUnknown; 8591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (protocol == ETHERTYPE_IP) { 8691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart family = IPAddress::kFamilyIPv4; 8791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } else if (protocol == ETHERTYPE_IPV6) { 8891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart family = IPAddress::kFamilyIPv6; 8991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } else { 9091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart NOTIMPLEMENTED() << "Packet has unknown protocol " 9191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << protocol; 9291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 9391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 9491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (header.ar_hln != ETH_ALEN) { 9591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Packet has unexpected hardware address length " 9691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << static_cast<int>(header.ar_hln) << "; expected " << ETH_ALEN; 9791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 9891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 9991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart size_t ip_address_length = IPAddress::GetAddressLength(family); 10091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (header.ar_pln != ip_address_length) { 10191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Packet has unexpected protocol address length " 10291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << static_cast<int>(header.ar_hln) << "; expected " 10391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << ip_address_length; 10491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 10591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 1067fab89734d88724a288e96a9996b15548c5294c7Ben Chan const uint16_t operation = ntohs(header.ar_op); 107417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart if (operation != ARPOP_REPLY && operation != ARPOP_REQUEST) { 108417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart NOTIMPLEMENTED() << "Packet is not an ARP reply or request but of type " 10991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << operation; 11091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 11191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 11291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart size_t min_packet_size = 11391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart sizeof(header) + 2 * ip_address_length + 2 * ETH_ALEN; 11491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (packet.GetLength() < min_packet_size) { 11591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart NOTIMPLEMENTED() << "Packet of size " 11691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << packet.GetLength() 11791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << " is too small to contain entire ARP payload; " 11891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << "expected at least " 11991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << min_packet_size; 12091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 12191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 122417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart operation_ = operation; 12391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart local_mac_address_ = packet.GetSubstring(sizeof(header), ETH_ALEN); 12491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart local_ip_address_ = IPAddress(family, packet.GetSubstring( 12591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart sizeof(header) + ETH_ALEN, ip_address_length)); 12691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_mac_address_ = packet.GetSubstring( 12791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart sizeof(header) + ETH_ALEN + ip_address_length, ETH_ALEN); 12891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_ip_address_ = IPAddress(family, packet.GetSubstring( 12991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart sizeof(header) + ETH_ALEN * 2 + ip_address_length, ip_address_length)); 13091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return true; 13191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart} 13291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 13391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart// Output a payload from local parameters. 134a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool ArpPacket::FormatRequest(ByteString* packet) const { 13591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (!local_ip_address_.IsValid() || !remote_ip_address_.IsValid()) { 13691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Local or remote IP address is not valid."; 13791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 13891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 13991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (local_ip_address_.family() != remote_ip_address_.family()) { 14091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Local and remote IP address families do not match!"; 14191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 14291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 1437fab89734d88724a288e96a9996b15548c5294c7Ben Chan uint16_t protocol; 14491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart IPAddress::Family family = local_ip_address_.family(); 14591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (family == IPAddress::kFamilyIPv4) { 14691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart protocol = ETHERTYPE_IP; 14791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } else if (family == IPAddress::kFamilyIPv6) { 14891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart protocol = ETHERTYPE_IPV6; 14991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } else { 15091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart NOTIMPLEMENTED() << "Address family " 15191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << IPAddress::GetAddressFamilyName(family) 15291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart << " is not supported."; 15391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 15491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 15591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart size_t ip_address_length = IPAddress::GetAddressLength(family); 1563a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko CHECK(ip_address_length < std::numeric_limits<uint8_t>::max()); 15791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart if (local_mac_address_.GetLength() != ETH_ALEN || 15891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart remote_mac_address_.GetLength() != ETH_ALEN) { 15991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart LOG(ERROR) << "Local or remote MAC address length is incorrect."; 16091a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return false; 16191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart } 16291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 16391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart arphdr header; 16491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart header.ar_hrd = htons(ARPHRD_ETHER); 16591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart header.ar_pro = htons(protocol); 16691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart header.ar_hln = ETH_ALEN; 16791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart header.ar_pln = ip_address_length; 16891a5aac3d03883be7d652096b1c018298096edcdPaul Stewart header.ar_op = htons(ARPOP_REQUEST); 16991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 170a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart *packet = ByteString(reinterpret_cast<const unsigned char*>(&header), 17191a5aac3d03883be7d652096b1c018298096edcdPaul Stewart sizeof(header)); 17291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 17391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart packet->Append(local_mac_address_); 17491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart packet->Append(local_ip_address_.address()); 17591a5aac3d03883be7d652096b1c018298096edcdPaul Stewart packet->Append(remote_mac_address_); 17691a5aac3d03883be7d652096b1c018298096edcdPaul Stewart packet->Append(remote_ip_address_.address()); 17791a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 178ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewart if (packet->GetLength() < kMinPayloadSize) { 179ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewart packet->Append(ByteString(kMinPayloadSize - packet->GetLength())); 180ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewart } 181ac1328e5143f6ee0054d5cb2f7d17754c16a3814Paul Stewart 18291a5aac3d03883be7d652096b1c018298096edcdPaul Stewart return true; 18391a5aac3d03883be7d652096b1c018298096edcdPaul Stewart} 18491a5aac3d03883be7d652096b1c018298096edcdPaul Stewart 185417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewartbool ArpPacket::IsReply() const { 186417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart return operation_ == ARPOP_REPLY; 187417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart} 188417e5f079a1ccbc068c67f9cbf34f13c40330abcPaul Stewart 18991a5aac3d03883be7d652096b1c018298096edcdPaul Stewart} // namespace shill 190