mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
Libc: implement getifaddrs
Implement getifaddrs and freeifaddrs within the libc using socket control files at the VFS. Add an "address" and "netmask" file to the lwIP plugin. Only a single IPv4 address is initially supported, and the broadcast address returned will never be valid. Fixes #3439
This commit is contained in:
parent
ab017607a2
commit
36111a2edf
@ -256,6 +256,8 @@ class Lwip::Nic_netif
|
||||
|
||||
virtual ~Nic_netif() { }
|
||||
|
||||
Lwip::netif& lwip_netif() { return _netif; }
|
||||
|
||||
/**
|
||||
* Status callback to override in subclass
|
||||
*/
|
||||
|
@ -263,6 +263,8 @@ gethostbyaddr_r T
|
||||
gethostbyname W
|
||||
gethostid T
|
||||
gethostname T
|
||||
getifaddrs T
|
||||
freeifaddrs T
|
||||
getline T
|
||||
getloadavg T
|
||||
getlogin T
|
||||
|
@ -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 *))
|
||||
|
@ -1,5 +1,3 @@
|
||||
#include <base/debug.h>
|
||||
|
||||
/*
|
||||
* \brief Libc pseudo plugin for socket fs
|
||||
* \author Christian Helmuth
|
||||
@ -34,6 +32,8 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
|
||||
/* 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 **
|
||||
****************************/
|
||||
|
@ -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<ADDRESS_FILE_SIZE>
|
||||
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<ADDRESS_FILE_SIZE>
|
||||
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);
|
||||
|
@ -15,9 +15,49 @@
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
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];
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user