ncsid: Import from gBMC

This is the initial code drop from gBMC.

Google-Bug-Id: 179618516
Upstream: 1e71af914bc8c54d8b91d0a1cf377e2696713c2f
Change-Id: Ic653e8271dacd205e04f2bc713071ef2ec5936a4
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/ncsid/src/net_iface.cpp b/ncsid/src/net_iface.cpp
new file mode 100644
index 0000000..753ab74
--- /dev/null
+++ b/ncsid/src/net_iface.cpp
@@ -0,0 +1,120 @@
+#include "net_iface.h"
+
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+
+namespace net
+{
+
+IFaceBase::IFaceBase(const std::string& name) : name_{name}
+{
+    if (name.size() >= IFNAMSIZ)
+    {
+        throw std::length_error("Interface name is too long");
+    }
+}
+
+int IFaceBase::get_index() const
+{
+    struct ifreq ifr;
+    std::memset(&ifr, 0, sizeof(ifr));
+    int ret = ioctl(SIOCGIFINDEX, &ifr);
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    return ifr.ifr_ifindex;
+}
+
+int IFaceBase::set_sock_flags(int sockfd, short flags) const
+{
+    return mod_sock_flags(sockfd, flags, true);
+}
+
+int IFaceBase::clear_sock_flags(int sockfd, short flags) const
+{
+    return mod_sock_flags(sockfd, flags, false);
+}
+
+int IFaceBase::mod_sock_flags(int sockfd, short flags, bool set) const
+{
+    struct ifreq ifr;
+    std::memset(&ifr, 0, sizeof(ifr));
+
+    int ret = ioctl_sock(sockfd, SIOCGIFFLAGS, &ifr);
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    if (set)
+    {
+        ifr.ifr_flags |= flags;
+    }
+    else
+    {
+        ifr.ifr_flags &= ~flags;
+    }
+    return ioctl_sock(sockfd, SIOCSIFFLAGS, &ifr);
+}
+
+int IFace::ioctl_sock(int sockfd, int request, struct ifreq* ifr) const
+{
+    if (ifr == nullptr)
+    {
+        return -1;
+    }
+
+    /* Avoid string truncation. */
+    size_t len = name_.length();
+    if (len + 1 >= sizeof(ifr->ifr_name))
+    {
+        return -1;
+    }
+
+    std::memcpy(ifr->ifr_name, name_.c_str(), len);
+    ifr->ifr_name[len] = 0;
+
+    return ::ioctl(sockfd, request, ifr);
+}
+
+int IFace::bind_sock(int sockfd, struct sockaddr_ll* saddr) const
+{
+    if (saddr == nullptr)
+    {
+        return -1;
+    }
+
+    saddr->sll_ifindex = get_index();
+
+    return bind(sockfd, reinterpret_cast<struct sockaddr*>(saddr),
+                sizeof(*saddr));
+}
+
+int IFace::ioctl(int request, struct ifreq* ifr) const
+{
+    if (ifr == nullptr)
+    {
+        return -1;
+    }
+
+    int tempsock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (tempsock < 0)
+    {
+        return tempsock;
+    }
+
+    int ret = ioctl_sock(tempsock, request, ifr);
+    close(tempsock);
+
+    return ret;
+}
+
+} // namespace net