/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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); }