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