Back to index

glibc  2.9
check_native.c
Go to the documentation of this file.
00001 /* Determine whether interfaces use native transport.  Linux version.
00002    Copyright (C) 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <errno.h>
00022 #include <ifaddrs.h>
00023 #include <stddef.h>
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <time.h>
00027 #include <unistd.h>
00028 #include <net/if.h>
00029 #include <net/if_arp.h>
00030 #include <sys/ioctl.h>
00031 
00032 #include <asm/types.h>
00033 #include <linux/netlink.h>
00034 #include <linux/rtnetlink.h>
00035 
00036 #include <not-cancel.h>
00037 
00038 
00039 void
00040 __check_native (uint32_t a1_index, int *a1_native,
00041               uint32_t a2_index, int *a2_native)
00042 {
00043   int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00044 
00045   struct sockaddr_nl nladdr;
00046   memset (&nladdr, '\0', sizeof (nladdr));
00047   nladdr.nl_family = AF_NETLINK;
00048 
00049   socklen_t addr_len = sizeof (nladdr);
00050 
00051   if (fd < 0
00052       || __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) != 0
00053       || __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) != 0)
00054     return;
00055 
00056   pid_t pid = nladdr.nl_pid;
00057   struct req
00058   {
00059     struct nlmsghdr nlh;
00060     struct rtgenmsg g;
00061     /* struct rtgenmsg consists of a single byte.  This means there
00062        are three bytes of padding included in the REQ definition.
00063        We make them explicit here.  */
00064     char pad[3];
00065   } req;
00066 
00067   req.nlh.nlmsg_len = sizeof (req);
00068   req.nlh.nlmsg_type = RTM_GETLINK;
00069   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
00070   req.nlh.nlmsg_pid = 0;
00071   req.nlh.nlmsg_seq = time (NULL);
00072   req.g.rtgen_family = AF_UNSPEC;
00073 
00074   assert (sizeof (req) - offsetof (struct req, pad) == 3);
00075   memset (req.pad, '\0', sizeof (req.pad));
00076 
00077   memset (&nladdr, '\0', sizeof (nladdr));
00078   nladdr.nl_family = AF_NETLINK;
00079 
00080 #ifdef PAGE_SIZE
00081   /* Help the compiler optimize out the malloc call if PAGE_SIZE
00082      is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
00083   const size_t buf_size = PAGE_SIZE;
00084 #else
00085   const size_t buf_size = __getpagesize ();
00086 #endif
00087   bool use_malloc = false;
00088   char *buf;
00089 
00090   if (__libc_use_alloca (buf_size))
00091     buf = alloca (buf_size);
00092   else
00093     {
00094       buf = malloc (buf_size);
00095       if (buf != NULL)
00096        use_malloc = true;
00097       else
00098        goto out_fail;
00099     }
00100 
00101   struct iovec iov = { buf, buf_size };
00102 
00103   if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
00104                                 (struct sockaddr *) &nladdr,
00105                                 sizeof (nladdr))) < 0)
00106     goto out_fail;
00107 
00108   bool done = false;
00109   do
00110     {
00111       struct msghdr msg =
00112        {
00113          (void *) &nladdr, sizeof (nladdr),
00114          &iov, 1,
00115          NULL, 0,
00116          0
00117        };
00118 
00119       ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
00120       if (read_len < 0)
00121        goto out_fail;
00122 
00123       if (msg.msg_flags & MSG_TRUNC)
00124        goto out_fail;
00125 
00126       struct nlmsghdr *nlmh;
00127       for (nlmh = (struct nlmsghdr *) buf;
00128           NLMSG_OK (nlmh, (size_t) read_len);
00129           nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
00130        {
00131          if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid
00132              || nlmh->nlmsg_seq != req.nlh.nlmsg_seq)
00133            continue;
00134 
00135          if (nlmh->nlmsg_type == RTM_NEWLINK)
00136            {
00137              struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlmh);
00138              int native = (ifim->ifi_type != ARPHRD_TUNNEL6
00139                          && ifim->ifi_type != ARPHRD_TUNNEL
00140                          && ifim->ifi_type != ARPHRD_SIT);
00141 
00142              if (a1_index == ifim->ifi_index)
00143               {
00144                 *a1_native = native;
00145                 a1_index = 0xffffffffu;
00146               }
00147              if (a2_index == ifim->ifi_index)
00148               {
00149                 *a2_native = native;
00150                 a2_index = 0xffffffffu;
00151               }
00152 
00153              if (a1_index == 0xffffffffu
00154                 && a2_index == 0xffffffffu)
00155               goto out;
00156            }
00157          else if (nlmh->nlmsg_type == NLMSG_DONE)
00158            /* We found the end, leave the loop.  */
00159            done = true;
00160        }
00161     }
00162   while (! done);
00163 
00164  out:
00165   close_not_cancel_no_status (fd);
00166 
00167   return;
00168 
00169 out_fail:
00170   if (use_malloc)
00171     free (buf);
00172 }