1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00
This commit is contained in:
Jakub Jelinek
2007-07-12 18:26:36 +00:00
parent 7d58530341
commit 0ecb606cb6
6215 changed files with 494638 additions and 305010 deletions

View File

@ -1,5 +1,5 @@
/* getifaddrs -- get names and addresses of all network interfaces
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -17,6 +17,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <ifaddrs.h>
@ -24,6 +25,7 @@
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
@ -84,13 +86,14 @@ __netlink_free_handle (struct netlink_handle *h)
}
int
static int
__netlink_sendreq (struct netlink_handle *h, int type)
{
struct
struct req
{
struct nlmsghdr nlh;
struct rtgenmsg g;
char pad[0];
} req;
struct sockaddr_nl nladdr;
@ -103,6 +106,8 @@ __netlink_sendreq (struct netlink_handle *h, int type)
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = h->seq;
req.g.rtgen_family = AF_UNSPEC;
if (sizeof (req) != offsetof (struct req, pad))
memset (req.pad, '\0', sizeof (req) - offsetof (struct req, pad));
memset (&nladdr, '\0', sizeof (nladdr));
nladdr.nl_family = AF_NETLINK;
@ -114,16 +119,40 @@ __netlink_sendreq (struct netlink_handle *h, int type)
int
__netlink_receive (struct netlink_handle *h)
__netlink_request (struct netlink_handle *h, int type)
{
struct netlink_res *nlm_next;
char buf[4096];
struct iovec iov = { buf, sizeof (buf) };
struct sockaddr_nl nladdr;
struct nlmsghdr *nlmh;
int read_len;
ssize_t read_len;
bool done = false;
#ifdef PAGE_SIZE
/* Help the compiler optimize out the malloc call if PAGE_SIZE
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
const size_t buf_size = PAGE_SIZE;
#else
const size_t buf_size = __getpagesize ();
#endif
bool use_malloc = false;
char *buf;
if (__libc_use_alloca (buf_size))
buf = alloca (buf_size);
else
{
buf = malloc (buf_size);
if (buf != NULL)
use_malloc = true;
else
goto out_fail;
}
struct iovec iov = { buf, buf_size };
if (__netlink_sendreq (h, type) < 0)
goto out_fail;
while (! done)
{
struct msghdr msg =
@ -136,33 +165,25 @@ __netlink_receive (struct netlink_handle *h)
read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
if (read_len < 0)
return -1;
goto out_fail;
if (msg.msg_flags & MSG_TRUNC)
return -1;
if (nladdr.nl_pid != 0)
continue;
nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
+ read_len);
if (nlm_next == NULL)
return -1;
nlm_next->next = NULL;
nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
nlm_next->size = read_len;
nlm_next->seq = h->seq;
if (h->nlm_list == NULL)
h->nlm_list = nlm_next;
else
h->end_ptr->next = nlm_next;
h->end_ptr = nlm_next;
if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
goto out_fail;
size_t count = 0;
size_t remaining_len = read_len;
for (nlmh = (struct nlmsghdr *) buf;
NLMSG_OK (nlmh, (size_t) read_len);
nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
NLMSG_OK (nlmh, remaining_len);
nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
{
if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != h->pid
if ((pid_t) nlmh->nlmsg_pid != h->pid
|| nlmh->nlmsg_seq != h->seq)
continue;
++count;
if (nlmh->nlmsg_type == NLMSG_DONE)
{
/* We found the end, leave the loop. */
@ -176,11 +197,38 @@ __netlink_receive (struct netlink_handle *h)
errno = EIO;
else
errno = -nlerr->error;
return -1;
goto out_fail;
}
}
/* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
there is no point to record it. */
if (count == 0)
continue;
nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
+ read_len);
if (nlm_next == NULL)
goto out_fail;
nlm_next->next = NULL;
nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
nlm_next->size = read_len;
nlm_next->seq = h->seq;
if (h->nlm_list == NULL)
h->nlm_list = nlm_next;
else
h->end_ptr->next = nlm_next;
h->end_ptr = nlm_next;
}
if (use_malloc)
free (buf);
return 0;
out_fail:
if (use_malloc)
free (buf);
return -1;
}
@ -268,12 +316,11 @@ getifaddrs (struct ifaddrs **ifap)
unsigned int i, newlink, newaddr, newaddr_idx;
int *map_newlink_data;
size_t ifa_data_size = 0; /* Size to allocate for all ifa_data. */
char *ifa_data_ptr; /* Pointer to the unused part of memory for
char *ifa_data_ptr; /* Pointer to the unused part of memory for
ifa_data. */
int result = 0;
if (ifap)
*ifap = NULL;
*ifap = NULL;
if (! __no_netlink_support && __netlink_open (&nh) < 0)
{
@ -288,28 +335,20 @@ getifaddrs (struct ifaddrs **ifap)
#endif
/* Tell the kernel that we wish to get a list of all
active interfaces. */
if (__netlink_sendreq (&nh, RTM_GETLINK) < 0)
{
result = -1;
goto exit_close;
}
/* Collect all data for every interface. */
if (__netlink_receive (&nh) < 0)
active interfaces, collect all data for every interface. */
if (__netlink_request (&nh, RTM_GETLINK) < 0)
{
result = -1;
goto exit_free;
}
/* Now ask the kernel for all addresses which are assigned
to an interface. Since we store the addresses after the
interfaces in the list, we will later always find the
interface before the corresponding addresses. */
to an interface and collect all data for every interface.
Since we store the addresses after the interfaces in the
list, we will later always find the interface before the
corresponding addresses. */
++nh.seq;
if (__netlink_sendreq (&nh, RTM_GETADDR) < 0
/* Collect all data for every interface. */
|| __netlink_receive (&nh) < 0)
if (__netlink_request (&nh, RTM_GETADDR) < 0)
{
result = -1;
goto exit_free;
@ -327,7 +366,7 @@ getifaddrs (struct ifaddrs **ifap)
continue;
/* Walk through all entries we got from the kernel and look, which
message type they contain. */
message type they contain. */
for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
{
/* Check if the message is what we want. */
@ -423,7 +462,7 @@ getifaddrs (struct ifaddrs **ifap)
/* Interfaces are stored in the first "newlink" entries
of our list, starting in the order as we got from the
kernel. */
ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
map_newlink_data, newlink);
ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
@ -762,13 +801,10 @@ getifaddrs (struct ifaddrs **ifap)
memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
}
if (ifap != NULL)
*ifap = &ifas[0].ifa;
*ifap = &ifas[0].ifa;
exit_free:
__netlink_free_handle (&nh);
exit_close:
__netlink_close (&nh);
return result;