summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/check_native.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-11-14 06:58:35 +0000
committerUlrich Drepper <drepper@redhat.com>2007-11-14 06:58:35 +0000
commit773e79b3162dff01e080cb152ff77945244f5a17 (patch)
treec5b1f11c79b36c6c1d02e80b0f6e00274ea6e586 /sysdeps/unix/sysv/linux/check_native.c
parente458144c99ddc00769ffa6bd367c21d37e879d83 (diff)
downloadglibc-773e79b3162dff01e080cb152ff77945244f5a17.tar.gz
* include/ifaddrs.h: Remove in6ai_temporary.
(struct in6addrinfo): Add index element. Declare __check_native. * inet/Makefile (aux): Add check_native. * sysdeps/unix/sysv/linux/check_native.c: New file. * sysdeps/unix/sysv/linux/check_pf.c: No need to recognize IFA_F_TEMPORARY. Pass back ifa_index. * sysdeps/posix/getaddrinfo.c: Remove netlink compatibility code. (rfc3484_sort): Add new parameter. Implement rule 7 correctly: call __check_native if necessary. (getaddrinfo): Fill in index field. Use qsort_r instead of qsort to sort addresses. Pass information about the results. * posix/tst-rfc3484.c: Adjust for addition of index field and change of rfc3484_sort interface. * posix/tst-rfc3484-2.c: Likewise.
Diffstat (limited to 'sysdeps/unix/sysv/linux/check_native.c')
-rw-r--r--sysdeps/unix/sysv/linux/check_native.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/check_native.c b/sysdeps/unix/sysv/linux/check_native.c
new file mode 100644
index 0000000000..9b1bb61941
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/check_native.c
@@ -0,0 +1,209 @@
+/* Determine whether interfaces use native transport. Linux version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <not-cancel.h>
+
+
+void
+__check_native (uint32_t a1_index, int *a1_native,
+ uint32_t a2_index, int *a2_native)
+{
+ int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+ struct sockaddr_nl nladdr;
+ memset (&nladdr, '\0', sizeof (nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ socklen_t addr_len = sizeof (nladdr);
+
+ if (fd < 0
+ || __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) != 0
+ || __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) != 0)
+ return;
+
+ pid_t pid = nladdr.nl_pid;
+ struct req
+ {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ /* struct rtgenmsg consists of a single byte. This means there
+ are three bytes of padding included in the REQ definition.
+ We make them explicit here. */
+ char pad[3];
+ } req;
+
+ req.nlh.nlmsg_len = sizeof (req);
+ req.nlh.nlmsg_type = RTM_GETLINK;
+ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = time (NULL);
+ req.g.rtgen_family = AF_UNSPEC;
+
+ assert (sizeof (req) - offsetof (struct req, pad) == 3);
+ memset (req.pad, '\0', sizeof (req.pad));
+
+ memset (&nladdr, '\0', sizeof (nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+#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 (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
+ (struct sockaddr *) &nladdr,
+ sizeof (nladdr))) < 0)
+ goto out_fail;
+
+ bool done = false;
+ int v4fd = -1;
+ do
+ {
+ struct msghdr msg =
+ {
+ (void *) &nladdr, sizeof (nladdr),
+ &iov, 1,
+ NULL, 0,
+ 0
+ };
+
+ ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
+ if (read_len < 0)
+ goto out_fail;
+
+ if (msg.msg_flags & MSG_TRUNC)
+ goto out_fail;
+
+ struct nlmsghdr *nlmh;
+ for (nlmh = (struct nlmsghdr *) buf;
+ NLMSG_OK (nlmh, (size_t) read_len);
+ nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
+ {
+ if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid
+ || nlmh->nlmsg_seq != req.nlh.nlmsg_seq)
+ continue;
+
+ if (nlmh->nlmsg_type == RTM_NEWLINK)
+ {
+ /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
+ know the size before creating the list to allocate enough
+ memory. */
+ struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlmh);
+ struct rtattr *rta = IFLA_RTA (ifim);
+ size_t rtasize = IFLA_PAYLOAD (nlmh);
+ int index = ifim->ifi_index;
+
+ if (a1_index == index || a2_index == index)
+ while (RTA_OK (rta, rtasize))
+ {
+ char *rta_data = RTA_DATA (rta);
+ size_t rta_payload = RTA_PAYLOAD (rta);
+
+ if (rta->rta_type == IFLA_IFNAME)
+ {
+ struct ifreq ifr;
+ *((char *) mempcpy (ifr.ifr_name, rta_data,
+ rta_payload))= '\0';
+
+ if (v4fd == -1)
+ {
+ v4fd = __socket (AF_INET, SOCK_DGRAM, 0);
+ if (v4fd == -1)
+ return;
+ }
+
+ if (__ioctl (v4fd, SIOCGIFHWADDR, &ifr) >= 0)
+ {
+ int native
+ = (ifr.ifr_hwaddr.sa_family != ARPHRD_TUNNEL6
+ && ifr.ifr_hwaddr.sa_family != ARPHRD_TUNNEL
+ && ifr.ifr_hwaddr.sa_family != ARPHRD_SIT);
+
+ if (a1_index == index)
+ {
+ *a1_native = native;
+ a1_index = 0xffffffffu;
+ }
+ if (a2_index == index)
+ {
+ *a2_native = native;
+ a2_index = 0xffffffffu;
+ }
+
+ if (a1_index == 0xffffffffu
+ && a2_index == 0xffffffffu)
+ goto out;
+ }
+ break;
+ }
+
+ rta = RTA_NEXT (rta, rtasize);
+ }
+ }
+ else if (nlmh->nlmsg_type == NLMSG_DONE)
+ /* We found the end, leave the loop. */
+ done = true;
+ }
+ }
+ while (! done);
+
+ out:
+ close_not_cancel_no_status (fd);
+ if (v4fd != -1)
+ close_not_cancel_no_status (v4fd);
+
+ return;
+
+out_fail:
+ if (use_malloc)
+ free (buf);
+}