diff --git a/repos/libports/include/lwip/nic_netif.h b/repos/libports/include/lwip/nic_netif.h
index 687327376..2ee932bfc 100644
--- a/repos/libports/include/lwip/nic_netif.h
+++ b/repos/libports/include/lwip/nic_netif.h
@@ -256,6 +256,8 @@ class Lwip::Nic_netif
virtual ~Nic_netif() { }
+ Lwip::netif& lwip_netif() { return _netif; }
+
/**
* Status callback to override in subclass
*/
diff --git a/repos/libports/lib/symbols/libc b/repos/libports/lib/symbols/libc
index 4b8fd9ba5..69e67d1c4 100644
--- a/repos/libports/lib/symbols/libc
+++ b/repos/libports/lib/symbols/libc
@@ -263,6 +263,8 @@ gethostbyaddr_r T
gethostbyname W
gethostid T
gethostname T
+getifaddrs T
+freeifaddrs T
getline T
getloadavg T
getlogin T
diff --git a/repos/libports/src/lib/libc/dummies.cc b/repos/libports/src/lib/libc/dummies.cc
index b63dd3d40..40f25bc12 100644
--- a/repos/libports/src/lib/libc/dummies.cc
+++ b/repos/libports/src/lib/libc/dummies.cc
@@ -106,8 +106,6 @@ DUMMY(uid_t , 0, geteuid, (void))
DUMMY(gid_t , 0, getgid, (void))
DUMMY(int , -1, getgroups, (int, gid_t *))
DUMMY(struct hostent *, 0, gethostbyname, (const char *))
-DUMMY(int, -1, getifaddrs, (struct ifaddrs **))
-DUMMY(void, , freeifaddrs, (struct ifaddrs *ifp))
DUMMY(char *, 0, _getlogin, (void))
DUMMY(int , -1, getnameinfo, (const sockaddr *, socklen_t, char *, size_t, char *, size_t, int))
DUMMY(struct servent *, 0, getservbyname, (const char *, const char *))
diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.cc b/repos/libports/src/lib/libc/socket_fs_plugin.cc
index db5354e96..6464d30a3 100644
--- a/repos/libports/src/lib/libc/socket_fs_plugin.cc
+++ b/repos/libports/src/lib/libc/socket_fs_plugin.cc
@@ -1,5 +1,3 @@
-#include
-
/*
* \brief Libc pseudo plugin for socket fs
* \author Christian Helmuth
@@ -34,6 +32,8 @@
#include
#include
#include
+#include
+#include
/* libc-internal includes */
#include "socket_fs_plugin.h"
@@ -973,6 +973,61 @@ extern "C" int socket_fs_socket(int domain, int type, int protocol)
}
+static int read_ifaddr_file(sockaddr_in &sockaddr, Absolute_path const &path)
+{
+ Host_string address;
+ Port_string service;
+ *service.base() = '0';
+
+ {
+ FILE *fp = ::fopen(path.base(), "r");
+ if (!fp) return -1;
+
+ ::fscanf(fp, "%s\n", address.base());
+ ::fclose(fp);
+ }
+
+ try { sockaddr = sockaddr_in_struct(address, service); }
+ catch (...) { return -1; }
+
+ return 0;
+}
+
+
+extern "C" int getifaddrs(struct ifaddrs **ifap)
+{
+ static Genode::Lock lock;
+ Genode::Lock::Guard guard(lock);
+
+ // TODO: dual-stack / multi-homing
+
+ static sockaddr_in address;
+ static sockaddr_in netmask { 0 };
+ static sockaddr_in broadcast { 0 };
+
+ static ifaddrs ifaddr {
+ .ifa_name = "",
+ .ifa_flags = IFF_UP,
+ .ifa_addr = (sockaddr*)&address,
+ .ifa_netmask = (sockaddr*)&netmask,
+ .ifa_broadaddr = (sockaddr*)&broadcast,
+ };
+
+ *ifap = &ifaddr;
+
+ Absolute_path const root(Libc::config_socket());
+
+ if (read_ifaddr_file(address, Absolute_path("address", root.base())))
+ return -1;
+
+ read_ifaddr_file(netmask, Absolute_path("netmask", root.base()));
+ return 0;
+}
+
+
+extern "C" void freeifaddrs(struct ifaddrs *) { }
+
+
/****************************
** File-plugin operations **
****************************/
diff --git a/repos/libports/src/lib/vfs/lwip/vfs.cc b/repos/libports/src/lib/vfs/lwip/vfs.cc
index 2a287bc7b..279503f0e 100644
--- a/repos/libports/src/lib/vfs/lwip/vfs.cc
+++ b/repos/libports/src/lib/vfs/lwip/vfs.cc
@@ -84,6 +84,8 @@ extern "C" {
};
struct Lwip_handle;
struct Lwip_nameserver_handle;
+ struct Lwip_address_handle;
+ struct Lwip_netmask_handle;
struct Lwip_file_handle;
struct Lwip_dir_handle;
@@ -113,7 +115,8 @@ extern "C" {
enum {
PORT_STRLEN_MAX = 6, /* :65536 */
- ENDPOINT_STRLEN_MAX = IPADDR_STRLEN_MAX+PORT_STRLEN_MAX
+ ENDPOINT_STRLEN_MAX = IPADDR_STRLEN_MAX+PORT_STRLEN_MAX,
+ ADDRESS_FILE_SIZE = IPADDR_STRLEN_MAX+2,
};
struct Directory;
@@ -195,6 +198,66 @@ struct Lwip::Lwip_nameserver_handle final : Lwip_handle, private Nameserver_regi
};
+struct Lwip::Lwip_address_handle final : Lwip_handle
+{
+ Lwip::netif const &netif;
+
+ Lwip_address_handle(Vfs::File_system &fs, Allocator &alloc,
+ Lwip::netif &netif)
+ : Lwip_handle(fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY)
+ , netif(netif)
+ { }
+
+ Read_result read(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ using namespace Genode;
+
+ char address[IPADDR_STRLEN_MAX] { '\0' };
+
+ ipaddr_ntoa_r(&netif.ip_addr, address, IPADDR_STRLEN_MAX);
+
+ Genode::String
+ line((char const *)address, "\n");
+
+ size_t n = min(line.length(), count);
+ memcpy(dst, line.string(), n);
+ out_count = n;
+ return Read_result::READ_OK;
+ }
+};
+
+
+struct Lwip::Lwip_netmask_handle final : Lwip_handle
+{
+ Lwip::netif const &netif;
+
+ Lwip_netmask_handle(Vfs::File_system &fs, Allocator &alloc,
+ Lwip::netif &netif)
+ : Lwip_handle(fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY)
+ , netif(netif)
+ { }
+
+ Read_result read(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ using namespace Genode;
+
+ char netmask[IPADDR_STRLEN_MAX] { '\0' };
+
+ ipaddr_ntoa_r(&netif.netmask, netmask, IPADDR_STRLEN_MAX);
+
+ Genode::String
+ line((char const *)netmask, "\n");
+
+ size_t n = min(line.length(), count);
+ memcpy(dst, line.string(), n);
+ out_count = n;
+ return Read_result::READ_OK;
+ }
+};
+
+
struct Lwip::Lwip_file_handle final : Lwip_handle, private Lwip_handle_list::Element
{
friend class Lwip_handle_list;
@@ -1677,6 +1740,12 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
proc(path+3, _netif.udp_dir);
}
+ static bool match_address(char const *name) {
+ return (!strcmp(name, "address")); }
+
+ static bool match_netmask(char const *name) {
+ return (!strcmp(name, "netmask")); }
+
static bool match_nameserver(char const *name) {
return (!strcmp(name, "nameserver")); }
@@ -1710,7 +1779,9 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
char const *leaf_path(char const *path) override
{
if (*path == '/') ++path;
- if (match_nameserver(path))
+ if (match_address(path)
+ || match_netmask(path)
+ || match_nameserver(path))
return path;
char const *r = nullptr;
@@ -1726,6 +1797,12 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
st = Stat();
st.device = (Genode::addr_t)this;
+ if (match_address(path) || match_netmask(path)) {
+ st.size = ADDRESS_FILE_SIZE;
+ st.mode = STAT_MODE_FILE;
+ return STAT_OK;
+ }
+
if (match_nameserver(path)) {
st.size = IPADDR_STRLEN_MAX;
st.mode = STAT_MODE_FILE;
@@ -1764,6 +1841,18 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
*/
if (mode & OPEN_MODE_CREATE) return OPEN_ERR_NO_PERM;
+ if (match_address(path)) {
+ *out_handle = new (alloc)
+ Lwip_address_handle(*this, alloc, _netif.lwip_netif());
+ return OPEN_OK;
+ }
+
+ if (match_netmask(path)) {
+ *out_handle = new (alloc)
+ Lwip_netmask_handle(*this, alloc, _netif.lwip_netif());
+ return OPEN_OK;
+ }
+
if (match_nameserver(path)) {
*out_handle = new (alloc)
Lwip_nameserver_handle(*this, alloc, _netif.nameserver_handles);
diff --git a/repos/libports/src/test/libc_getaddrinfo/main.c b/repos/libports/src/test/libc_getaddrinfo/main.c
index cc6b82da9..2bb92645e 100644
--- a/repos/libports/src/test/libc_getaddrinfo/main.c
+++ b/repos/libports/src/test/libc_getaddrinfo/main.c
@@ -15,9 +15,49 @@
#include
#include
#include
+#include
int main(int argc, char **argv)
{
+ {
+ struct ifaddrs *addrs = NULL;
+
+ if (getifaddrs(&addrs)) {
+ printf("Check getifaddrs failed\n");
+ return ~0;
+ }
+
+ char ip_addr[NI_MAXHOST],
+ netmask[NI_MAXHOST],
+ broadcast[NI_MAXHOST],
+ sbuf[NI_MAXSERV];
+
+ if (getnameinfo(addrs->ifa_addr, addrs->ifa_addr->sa_len,
+ ip_addr, sizeof(ip_addr), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ {
+ printf("could not get address from getifaddrs\n");
+ return ~0;
+ }
+
+ if (getnameinfo(addrs->ifa_netmask, addrs->ifa_netmask->sa_len,
+ netmask, sizeof(netmask), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ {
+ printf("could not get netmask from getifaddrs\n");
+ }
+
+ if (getnameinfo(addrs->ifa_broadaddr, addrs->ifa_broadaddr->sa_len,
+ broadcast, sizeof(broadcast), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ {
+ printf("could not get broadcast from getifaddrs\n");
+ }
+
+ freeifaddrs(addrs);
+ printf("getifaddrs ip_addr=%s, netmask=%s broadcast=%s\n", ip_addr, netmask, broadcast);
+ }
+
struct addrinfo hints;
char ipstr[INET6_ADDRSTRLEN];