patchpanel: ndproxy: assign public v6 addr to guest-facing ifs

Currently there is no public IPv6 address assigned on the
guest-facing interfaces (arc bridges and taps) when device is on
IPv6 network. This is causing Linux choosing a wrong src address
on packets directly originated from host to guest and drop the
returning traffic.

This patch generates an EUI-64 address based on virtual interface
MAC address upon receiving an RA, and add it to the interface.

BUG=chromium:1069985
TEST=unit;fuzz
TEST=manual(deploy on octopus and verify pinging penguin from host)

Change-Id: Id3ae953df6b3c84411461294bbc8dbd236cef901
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2428652
Tested-by: Taoyu Li <taoyl@chromium.org>
Reviewed-by: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
Commit-Queue: Taoyu Li <taoyl@chromium.org>
diff --git a/patchpanel/net_util.cc b/patchpanel/net_util.cc
index a5a2a60..2fd9e28 100644
--- a/patchpanel/net_util.cc
+++ b/patchpanel/net_util.cc
@@ -121,6 +121,20 @@
   return true;
 }
 
+bool GenerateEUI64Address(in6_addr* address,
+                          const in6_addr& prefix,
+                          const MacAddress& mac) {
+  // RFC 4291, Appendix A: Insert 0xFF and 0xFE to form EUI-64, then flip
+  // universal/local bit
+  memcpy(address, &prefix, sizeof(in6_addr));
+  memcpy(&(address->s6_addr[8]), &(mac[0]), 3);
+  memcpy(&(address->s6_addr[13]), &(mac[3]), 3);
+  address->s6_addr[11] = 0xff;
+  address->s6_addr[12] = 0xfe;
+  address->s6_addr[8] ^= 0x2;
+  return true;
+}
+
 void SetSockaddrIn(struct sockaddr* sockaddr, uint32_t addr) {
   struct sockaddr_in* sockaddr_in =
       reinterpret_cast<struct sockaddr_in*>(sockaddr);