Merge "Explicit binary op order for both gcc and clang/llvm."
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
index c869420..b66883e 100644
--- a/libc/bionic/ifaddrs.cpp
+++ b/libc/bionic/ifaddrs.cpp
@@ -29,6 +29,7 @@
 #include <ifaddrs.h>
 
 #include <errno.h>
+#include <linux/if_packet.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <net/if.h>
@@ -93,6 +94,13 @@
       ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask);
   }
 
+  void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) {
+    sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(&addr);
+    sll->sll_ifindex = ifindex;
+    sll->sll_hatype = hatype;
+    sll->sll_halen = halen;
+  }
+
  private:
   // Returns a pointer to the first byte in the address data (which is
   // stored in network byte order).
@@ -103,6 +111,9 @@
     } else if (family == AF_INET6) {
       sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
       return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
+    } else if (family == AF_PACKET) {
+      sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ss);
+      return reinterpret_cast<uint8_t*>(&sll->sll_addr);
     }
     return nullptr;
   }
@@ -127,11 +138,21 @@
     rtattr* rta = IFLA_RTA(ifi);
     size_t rta_len = IFLA_PAYLOAD(hdr);
     while (RTA_OK(rta, rta_len)) {
-      if (rta->rta_type == IFLA_IFNAME) {
-        if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
-          memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
-          new_addr->ifa.ifa_name = new_addr->name;
-        }
+      if (rta->rta_type == IFLA_ADDRESS) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) {
+            new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
+          }
+      } else if (rta->rta_type == IFLA_BROADCAST) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) {
+            new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
+          }
+      } else if (rta->rta_type == IFLA_IFNAME) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
+            memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->ifa.ifa_name = new_addr->name;
+          }
       }
       rta = RTA_NEXT(rta, rta_len);
     }
@@ -139,9 +160,9 @@
     ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
 
     // We should already know about this from an RTM_NEWLINK message.
-    ifaddrs_storage* addr = reinterpret_cast<ifaddrs_storage*>(*out);
+    const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out);
     while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) {
-      addr = reinterpret_cast<ifaddrs_storage*>(addr->ifa.ifa_next);
+      addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next);
     }
     // If this is an unknown interface, ignore whatever we're being told about it.
     if (addr == nullptr) return;
@@ -161,12 +182,12 @@
     while (RTA_OK(rta, rta_len)) {
       if (rta->rta_type == IFA_ADDRESS) {
         if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
-          addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
-          addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
+          new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+          new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
         }
       } else if (rta->rta_type == IFA_BROADCAST) {
         if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
-          addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+          new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
         }
       }
       rta = RTA_NEXT(rta, rta_len);
diff --git a/tests/Android.mk b/tests/Android.mk
index 0e84331..8e37a76 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -71,6 +71,7 @@
     malloc_test.cpp \
     math_test.cpp \
     mntent_test.cpp \
+    net_if_test.cpp \
     netdb_test.cpp \
     netinet_udp_test.cpp \
     pthread_test.cpp \
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index 67857cb..bbaaec3 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -18,6 +18,9 @@
 
 #include <ifaddrs.h>
 
+#include <linux/if_packet.h>
+#include <netinet/in.h>
+
 TEST(ifaddrs, freeifaddrs_null) {
   freeifaddrs(nullptr);
 }
@@ -28,11 +31,33 @@
   ASSERT_EQ(0, getifaddrs(&addrs));
   ASSERT_TRUE(addrs != nullptr);
 
-  bool saw_loopback = false;
+  // We can't say much about what network interfaces are available, but we can be pretty
+  // sure there's a loopback interface, and that it has IPv4, IPv6, and AF_PACKET entries.
+  ifaddrs* lo_inet4 = nullptr;
+  ifaddrs* lo_inet6 = nullptr;
+  ifaddrs* lo_packet = nullptr;
   for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
-    if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) saw_loopback = true;
+    if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) {
+      if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) lo_inet4 = addr;
+      else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET6) lo_inet6 = addr;
+      else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_PACKET) lo_packet = addr;
+    }
   }
-  ASSERT_TRUE(saw_loopback);
+
+  // Does the IPv4 entry look right?
+  ASSERT_TRUE(lo_inet4 != nullptr);
+  const sockaddr_in* sa_inet4 = reinterpret_cast<const sockaddr_in*>(lo_inet4->ifa_addr);
+  ASSERT_TRUE(ntohl(sa_inet4->sin_addr.s_addr) == INADDR_LOOPBACK);
+
+  // Does the IPv6 entry look right?
+  ASSERT_TRUE(lo_inet6 != nullptr);
+  const sockaddr_in6* sa_inet6 = reinterpret_cast<const sockaddr_in6*>(lo_inet6->ifa_addr);
+  ASSERT_TRUE(IN6_IS_ADDR_LOOPBACK(&sa_inet6->sin6_addr));
+
+  // Does the AF_PACKET entry look right?
+  ASSERT_TRUE(lo_packet != nullptr);
+  const sockaddr_ll* sa_ll = reinterpret_cast<const sockaddr_ll*>(lo_packet->ifa_addr);
+  ASSERT_EQ(6, sa_ll->sll_halen);
 
   freeifaddrs(addrs);
 }
diff --git a/tests/net_if_test.cpp b/tests/net_if_test.cpp
new file mode 100644
index 0000000..9f38411
--- /dev/null
+++ b/tests/net_if_test.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <net/if.h>
+
+#include <errno.h>
+
+#include <gtest/gtest.h>
+
+TEST(net_if, if_nametoindex_if_indextoname) {
+  unsigned index;
+  index = if_nametoindex("lo");
+  ASSERT_NE(index, 0U);
+
+  char buf[IF_NAMESIZE] = {};
+  char* name = if_indextoname(index, buf);
+  ASSERT_STREQ("lo", name);
+}
+
+TEST(net_if, if_nametoindex_fail) {
+  unsigned index = if_nametoindex("this-interface-does-not-exist");
+  ASSERT_EQ(0U, index);
+}