arc: Move platform2/arc/network/ to platform2/patchpanel

Next step in the arc-networkd -> patchpanel rename, this patch moves the
location of the code.

BUG=b:151879931
TEST=units,flashed image to atlas
TEST=tasts arc.PlayStore, crostini.LaunchTerminal.download

Change-Id: I1b5cf8d670e1631d46f6449b725395157bf88dde
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2115863
Tested-by: Garrick Evans <garrick@chromium.org>
Commit-Queue: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Eric Caruso <ejcaruso@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
diff --git a/patchpanel/ndproxy.h b/patchpanel/ndproxy.h
new file mode 100644
index 0000000..4a4427b
--- /dev/null
+++ b/patchpanel/ndproxy.h
@@ -0,0 +1,175 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_NDPROXY_H_
+#define PATCHPANEL_NDPROXY_H_
+
+#include <stdint.h>
+
+#include <net/ethernet.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <brillo/daemons/daemon.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+
+#include "patchpanel/mac_address_generator.h"
+#include "patchpanel/message_dispatcher.h"
+
+namespace patchpanel {
+
+// Forward ICMPv6 RS/RA/NS/NA mssages between network interfaces according to
+// RFC 4389. Support asymmetric proxy that RS will be proxied one-way from
+// guest interface to physical interface ('Outbound') and RA the other way back
+// ('Inbound'), as well as symmetric proxy among guest interfaces that only
+// NS/NA will be proxied.
+class NDProxy {
+ public:
+  static constexpr ssize_t kTranslateErrorNotICMPv6Frame = -1;
+  static constexpr ssize_t kTranslateErrorNotNDFrame = -2;
+  static constexpr ssize_t kTranslateErrorInsufficientLength = -3;
+  static constexpr ssize_t kTranslateErrorBufferMisaligned = -4;
+
+  NDProxy();
+  virtual ~NDProxy() = default;
+
+  ssize_t TranslateNDFrame(const uint8_t* in_frame,
+                           ssize_t frame_len,
+                           const MacAddress& local_mac_addr,
+                           uint8_t* out_frame);
+
+  // Given an extended |buffer|, find a proper frame buffer pointer so that
+  // pt > buffer, and start of IP header (pt + ETH_H_LEN) is 4-bytes aligned.
+  // In the worst case the size of usable buffer will be original size minus 3.
+  // 4x => 4x+2; 4x+1 => 4x+2; 4x+2 => 4x+2; 4x+3 => 4x+6
+  static const uint8_t* AlignFrameBuffer(const uint8_t* buffer) {
+    return buffer + 3 - (reinterpret_cast<uintptr_t>(buffer + 1) & 0x3);
+  }
+
+  static uint8_t* AlignFrameBuffer(uint8_t* buffer) {
+    return buffer + 3 - (reinterpret_cast<uintptr_t>(buffer + 1) & 0x3);
+  }
+
+  // Helper function to create a AF_PACKET socket suitable for frame read/write.
+  static base::ScopedFD PreparePacketSocket();
+
+  // Initialize the resources needed such as rtnl socket and dummy socket for
+  // ioctl. Return false if failed.
+  bool Init();
+
+  // Read one frame from AF_PACKET socket |fd| and process it. If proxying is
+  // needed, translated frame is sent out through the same socket.
+  void ReadAndProcessOneFrame(int fd);
+
+  // NDProxy can trigger a callback upon receiving NA frame with unicast IPv6
+  // address from guest OS interface.
+  void RegisterOnGuestIpDiscoveryHandler(
+      const base::Callback<void(const std::string&, const std::string&)>&
+          handler);
+
+  // To proxy between upstream interface and guest OS interface (eth0-arc_eth0)
+  // Outbound RS, inbound RA, and bidirectional NS/NA will be proxied.
+  bool AddInterfacePair(const std::string& ifname_physical,
+                        const std::string& ifname_guest);
+
+  // Remove a proxy interface pair.
+  bool RemoveInterfacePair(const std::string& ifname_physical,
+                           const std::string& ifname_guest);
+
+  // Remove all proxy interface pair with ifindex.
+  bool RemoveInterface(const std::string& ifname);
+
+ private:
+  // Data structure to store interface mapping for a certain kind of packet to
+  // be proxied. For example, {1: {2}, 2: {1}} means that packet from interfaces
+  // 1 and 2 will be proxied to each other.
+  using interface_mapping = std::map<int, std::set<int>>;
+
+  static void ReplaceMacInIcmpOption(uint8_t* frame,
+                                     ssize_t frame_len,
+                                     size_t nd_hdr_len,
+                                     uint8_t opt_type,
+                                     const MacAddress& target_mac);
+
+  // Get MAC address on a local interface through ioctl().
+  // Returns false upon failure.
+  virtual bool GetLocalMac(int if_id, MacAddress* mac_addr);
+
+  // Query kernel NDP table and get the MAC address of a certain IPv6 neighbor.
+  // Returns false when neighbor entry is not found.
+  virtual bool GetNeighborMac(const in6_addr& ipv6_addr, MacAddress* mac_addr);
+
+  interface_mapping* MapForType(uint8_t type);
+  bool IsGuestInterface(int ifindex);
+
+  // Socket used to communicate with kernel through ioctl. No real packet data
+  // goes through this socket.
+  base::ScopedFD dummy_fd_;
+  base::ScopedFD rtnl_fd_;
+
+  // Allocate slightly more space and adjust the buffer start location to
+  // make sure IP header is 4-bytes aligned.
+  uint8_t in_frame_buffer_extended_[IP_MAXPACKET + ETH_HLEN + 4];
+  uint8_t out_frame_buffer_extended_[IP_MAXPACKET + ETH_HLEN + 4];
+  uint8_t* in_frame_buffer_;
+  uint8_t* out_frame_buffer_;
+
+  interface_mapping if_map_rs_;
+  interface_mapping if_map_ra_;
+  interface_mapping if_map_ns_na_;
+
+  base::Callback<void(const std::string&, const std::string&)>
+      guest_discovery_handler_;
+
+  base::WeakPtrFactory<NDProxy> weak_factory_{this};
+
+  FRIEND_TEST(NDProxyTest, TranslateFrame);
+  DISALLOW_COPY_AND_ASSIGN(NDProxy);
+};
+
+// A wrapper class for running NDProxy in a daemon process. Control messages and
+// guest IP discovery messages are passed through |control_fd|.
+class NDProxyDaemon : public brillo::Daemon {
+ public:
+  explicit NDProxyDaemon(base::ScopedFD control_fd);
+  virtual ~NDProxyDaemon();
+
+ private:
+  // Overrides Daemon init callback. Returns 0 on success and < 0 on error.
+  int OnInit() override;
+  // FileDescriptorWatcher callbacks for new data on fd_.
+  void OnDataSocketReadReady();
+  // Callbacks to be registered to msg_dispatcher to handle control messages.
+  void OnParentProcessExit();
+  void OnDeviceMessage(const DeviceMessage& msg);
+
+  // Callback from NDProxy core when receive NA from guest
+  void OnGuestIpDiscovery(const std::string& ifname,
+                          const std::string& ip6addr);
+
+  // Utilize MessageDispatcher to watch control fd
+  std::unique_ptr<MessageDispatcher> msg_dispatcher_;
+
+  // Data fd and its watcher
+  base::ScopedFD fd_;
+  std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
+
+  NDProxy proxy_;
+
+  base::WeakPtrFactory<NDProxyDaemon> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(NDProxyDaemon);
+};
+
+}  // namespace patchpanel
+
+#endif  // PATCHPANEL_NDPROXY_H_