xref: /minix3/crypto/external/bsd/heimdal/dist/lib/roken/getifaddrs.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: getifaddrs.c,v 1.1.1.2 2014/04/24 12:45:52 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
9ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
10ebfedea0SLionel Sambuc  * are met:
11ebfedea0SLionel Sambuc  *
12ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc  *
15ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18ebfedea0SLionel Sambuc  *
19ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
20ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
21ebfedea0SLionel Sambuc  *    without specific prior written permission.
22ebfedea0SLionel Sambuc  *
23ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ebfedea0SLionel Sambuc  * SUCH DAMAGE.
34ebfedea0SLionel Sambuc  */
35ebfedea0SLionel Sambuc 
36ebfedea0SLionel Sambuc #include <config.h>
37ebfedea0SLionel Sambuc #include <krb5/roken.h>
38ebfedea0SLionel Sambuc 
39ebfedea0SLionel Sambuc #ifdef __osf__
40ebfedea0SLionel Sambuc /* hate */
41ebfedea0SLionel Sambuc struct rtentry;
42ebfedea0SLionel Sambuc struct mbuf;
43ebfedea0SLionel Sambuc #endif
44ebfedea0SLionel Sambuc #ifdef HAVE_NET_IF_H
45ebfedea0SLionel Sambuc #include <net/if.h>
46ebfedea0SLionel Sambuc #endif
47ebfedea0SLionel Sambuc 
48ebfedea0SLionel Sambuc #ifdef HAVE_SYS_SOCKIO_H
49ebfedea0SLionel Sambuc #include <sys/sockio.h>
50ebfedea0SLionel Sambuc #endif /* HAVE_SYS_SOCKIO_H */
51ebfedea0SLionel Sambuc 
52ebfedea0SLionel Sambuc #ifdef HAVE_NETINET_IN6_VAR_H
53ebfedea0SLionel Sambuc #include <netinet/in6_var.h>
54ebfedea0SLionel Sambuc #endif /* HAVE_NETINET_IN6_VAR_H */
55ebfedea0SLionel Sambuc 
56ebfedea0SLionel Sambuc #include <ifaddrs.h>
57ebfedea0SLionel Sambuc 
58ebfedea0SLionel Sambuc #ifdef __hpux
59ebfedea0SLionel Sambuc #define lifconf if_laddrconf
60ebfedea0SLionel Sambuc #define lifc_len iflc_len
61ebfedea0SLionel Sambuc #define lifc_buf iflc_buf
62ebfedea0SLionel Sambuc #define lifc_req iflc_req
63ebfedea0SLionel Sambuc 
64ebfedea0SLionel Sambuc #define lifreq if_laddrreq
65ebfedea0SLionel Sambuc #define lifr_addr iflr_addr
66ebfedea0SLionel Sambuc #define lifr_name iflr_name
67ebfedea0SLionel Sambuc #define lifr_dstaddr iflr_dstaddr
68ebfedea0SLionel Sambuc #define lifr_broadaddr iflr_broadaddr
69ebfedea0SLionel Sambuc #define lifr_flags iflr_flags
70ebfedea0SLionel Sambuc #define lifr_index iflr_index
71ebfedea0SLionel Sambuc #endif
72ebfedea0SLionel Sambuc 
73ebfedea0SLionel Sambuc #ifdef AF_NETLINK
74ebfedea0SLionel Sambuc 
75ebfedea0SLionel Sambuc /*
76ebfedea0SLionel Sambuc  * The linux - AF_NETLINK version of getifaddrs - from Usagi.
77ebfedea0SLionel Sambuc  * Linux does not return v6 addresses from SIOCGIFCONF.
78ebfedea0SLionel Sambuc  */
79ebfedea0SLionel Sambuc 
80ebfedea0SLionel Sambuc /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
81ebfedea0SLionel Sambuc 
82ebfedea0SLionel Sambuc /**************************************************************************
83ebfedea0SLionel Sambuc  * ifaddrs.c
84ebfedea0SLionel Sambuc  * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
85ebfedea0SLionel Sambuc  *
86ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
87ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
88ebfedea0SLionel Sambuc  * are met:
89ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
90ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
91ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
92ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
93ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
94ebfedea0SLionel Sambuc  * 3. Neither the name of the author nor the names of its contributors
95ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
96ebfedea0SLionel Sambuc  *    without specific prior written permission.
97ebfedea0SLionel Sambuc  *
98ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
99ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
100ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
101ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
102ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
103ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
104ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
105ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
106ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
107ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
108ebfedea0SLionel Sambuc  * SUCH DAMAGE.
109ebfedea0SLionel Sambuc  */
110ebfedea0SLionel Sambuc 
111ebfedea0SLionel Sambuc #include "config.h"
112ebfedea0SLionel Sambuc 
113ebfedea0SLionel Sambuc #include <string.h>
114ebfedea0SLionel Sambuc #include <time.h>
115ebfedea0SLionel Sambuc #include <malloc.h>
116ebfedea0SLionel Sambuc #include <errno.h>
117ebfedea0SLionel Sambuc #include <unistd.h>
118ebfedea0SLionel Sambuc 
119ebfedea0SLionel Sambuc #include <sys/socket.h>
120ebfedea0SLionel Sambuc #include <asm/types.h>
121ebfedea0SLionel Sambuc #include <linux/netlink.h>
122ebfedea0SLionel Sambuc #include <linux/rtnetlink.h>
123ebfedea0SLionel Sambuc #include <sys/types.h>
124ebfedea0SLionel Sambuc #include <sys/socket.h>
125ebfedea0SLionel Sambuc #include <sys/poll.h>
126ebfedea0SLionel Sambuc #include <netpacket/packet.h>
127ebfedea0SLionel Sambuc #include <net/ethernet.h>     /* the L2 protocols */
128ebfedea0SLionel Sambuc #include <sys/uio.h>
129ebfedea0SLionel Sambuc #include <net/if.h>
130ebfedea0SLionel Sambuc #include <net/if_arp.h>
131ebfedea0SLionel Sambuc #include <ifaddrs.h>
132ebfedea0SLionel Sambuc #include <netinet/in.h>
133ebfedea0SLionel Sambuc 
134ebfedea0SLionel Sambuc #define __set_errno(e) (errno = (e))
135ebfedea0SLionel Sambuc #define __close(fd) (close(fd))
136ebfedea0SLionel Sambuc #undef ifa_broadaddr
137ebfedea0SLionel Sambuc #define ifa_broadaddr ifa_dstaddr
138ebfedea0SLionel Sambuc #define IFA_NETMASK
139ebfedea0SLionel Sambuc 
140ebfedea0SLionel Sambuc /* ====================================================================== */
141ebfedea0SLionel Sambuc struct nlmsg_list{
142ebfedea0SLionel Sambuc     struct nlmsg_list *nlm_next;
143ebfedea0SLionel Sambuc     struct nlmsghdr *nlh;
144ebfedea0SLionel Sambuc     int size;
145ebfedea0SLionel Sambuc     time_t seq;
146ebfedea0SLionel Sambuc };
147ebfedea0SLionel Sambuc 
148ebfedea0SLionel Sambuc struct rtmaddr_ifamap {
149ebfedea0SLionel Sambuc   void *address;
150ebfedea0SLionel Sambuc   void *local;
151ebfedea0SLionel Sambuc #ifdef IFA_NETMASK
152ebfedea0SLionel Sambuc   void *netmask;
153ebfedea0SLionel Sambuc #endif
154ebfedea0SLionel Sambuc   void *broadcast;
155ebfedea0SLionel Sambuc #ifdef HAVE_IFADDRS_IFA_ANYCAST
156ebfedea0SLionel Sambuc   void *anycast;
157ebfedea0SLionel Sambuc #endif
158ebfedea0SLionel Sambuc   int address_len;
159ebfedea0SLionel Sambuc   int local_len;
160ebfedea0SLionel Sambuc #ifdef IFA_NETMASK
161ebfedea0SLionel Sambuc   int netmask_len;
162ebfedea0SLionel Sambuc #endif
163ebfedea0SLionel Sambuc   int broadcast_len;
164ebfedea0SLionel Sambuc #ifdef HAVE_IFADDRS_IFA_ANYCAST
165ebfedea0SLionel Sambuc   int anycast_len;
166ebfedea0SLionel Sambuc #endif
167ebfedea0SLionel Sambuc };
168ebfedea0SLionel Sambuc 
169ebfedea0SLionel Sambuc /* ====================================================================== */
170ebfedea0SLionel Sambuc static size_t
ifa_sa_len(sa_family_t family,int len)171ebfedea0SLionel Sambuc ifa_sa_len(sa_family_t family, int len)
172ebfedea0SLionel Sambuc {
173ebfedea0SLionel Sambuc   size_t size;
174ebfedea0SLionel Sambuc   switch(family){
175ebfedea0SLionel Sambuc   case AF_INET:
176ebfedea0SLionel Sambuc     size = sizeof(struct sockaddr_in);
177ebfedea0SLionel Sambuc     break;
178ebfedea0SLionel Sambuc   case AF_INET6:
179ebfedea0SLionel Sambuc     size = sizeof(struct sockaddr_in6);
180ebfedea0SLionel Sambuc     break;
181ebfedea0SLionel Sambuc   case AF_PACKET:
182ebfedea0SLionel Sambuc     size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
183ebfedea0SLionel Sambuc     if (size < sizeof(struct sockaddr_ll))
184ebfedea0SLionel Sambuc       size = sizeof(struct sockaddr_ll);
185ebfedea0SLionel Sambuc     break;
186ebfedea0SLionel Sambuc   default:
187ebfedea0SLionel Sambuc     size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
188ebfedea0SLionel Sambuc     if (size < sizeof(struct sockaddr))
189ebfedea0SLionel Sambuc       size = sizeof(struct sockaddr);
190ebfedea0SLionel Sambuc     break;
191ebfedea0SLionel Sambuc   }
192ebfedea0SLionel Sambuc   return size;
193ebfedea0SLionel Sambuc }
194ebfedea0SLionel Sambuc 
195ebfedea0SLionel Sambuc static void
ifa_make_sockaddr(sa_family_t family,struct sockaddr * sa,void * p,size_t len,uint32_t scope,uint32_t scopeid)196ebfedea0SLionel Sambuc ifa_make_sockaddr(sa_family_t family,
197ebfedea0SLionel Sambuc 		  struct sockaddr *sa,
198ebfedea0SLionel Sambuc 		  void *p, size_t len,
199ebfedea0SLionel Sambuc 		  uint32_t scope, uint32_t scopeid)
200ebfedea0SLionel Sambuc {
201ebfedea0SLionel Sambuc   if (sa == NULL) return;
202ebfedea0SLionel Sambuc   switch(family){
203ebfedea0SLionel Sambuc   case AF_INET:
204ebfedea0SLionel Sambuc     memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
205ebfedea0SLionel Sambuc     break;
206ebfedea0SLionel Sambuc   case AF_INET6:
207ebfedea0SLionel Sambuc     memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
208ebfedea0SLionel Sambuc     if (IN6_IS_ADDR_LINKLOCAL(p) ||
209ebfedea0SLionel Sambuc 	IN6_IS_ADDR_MC_LINKLOCAL(p)){
210ebfedea0SLionel Sambuc       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
211ebfedea0SLionel Sambuc     }
212ebfedea0SLionel Sambuc     break;
213ebfedea0SLionel Sambuc   case AF_PACKET:
214ebfedea0SLionel Sambuc     memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
215ebfedea0SLionel Sambuc     ((struct sockaddr_ll*)sa)->sll_halen = len;
216ebfedea0SLionel Sambuc     break;
217ebfedea0SLionel Sambuc   default:
218ebfedea0SLionel Sambuc     memcpy(sa->sa_data, p, len);	/*XXX*/
219ebfedea0SLionel Sambuc     break;
220ebfedea0SLionel Sambuc   }
221ebfedea0SLionel Sambuc   sa->sa_family = family;
222ebfedea0SLionel Sambuc #ifdef HAVE_SOCKADDR_SA_LEN
223ebfedea0SLionel Sambuc   sa->sa_len = ifa_sa_len(family, len);
224ebfedea0SLionel Sambuc #endif
225ebfedea0SLionel Sambuc }
226ebfedea0SLionel Sambuc 
227ebfedea0SLionel Sambuc #ifndef IFA_NETMASK
228ebfedea0SLionel Sambuc static struct sockaddr *
ifa_make_sockaddr_mask(sa_family_t family,struct sockaddr * sa,uint32_t prefixlen)229ebfedea0SLionel Sambuc ifa_make_sockaddr_mask(sa_family_t family,
230ebfedea0SLionel Sambuc 		       struct sockaddr *sa,
231ebfedea0SLionel Sambuc 		       uint32_t prefixlen)
232ebfedea0SLionel Sambuc {
233ebfedea0SLionel Sambuc   int i;
234ebfedea0SLionel Sambuc   char *p = NULL, c;
235ebfedea0SLionel Sambuc   uint32_t max_prefixlen = 0;
236ebfedea0SLionel Sambuc 
237ebfedea0SLionel Sambuc   if (sa == NULL) return NULL;
238ebfedea0SLionel Sambuc   switch(family){
239ebfedea0SLionel Sambuc   case AF_INET:
240ebfedea0SLionel Sambuc     memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
241ebfedea0SLionel Sambuc     p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
242ebfedea0SLionel Sambuc     max_prefixlen = 32;
243ebfedea0SLionel Sambuc     break;
244ebfedea0SLionel Sambuc   case AF_INET6:
245ebfedea0SLionel Sambuc     memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
246ebfedea0SLionel Sambuc     p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
247ebfedea0SLionel Sambuc #if 0	/* XXX: fill scope-id? */
248ebfedea0SLionel Sambuc     if (IN6_IS_ADDR_LINKLOCAL(p) ||
249ebfedea0SLionel Sambuc 	IN6_IS_ADDR_MC_LINKLOCAL(p)){
250ebfedea0SLionel Sambuc       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
251ebfedea0SLionel Sambuc     }
252ebfedea0SLionel Sambuc #endif
253ebfedea0SLionel Sambuc     max_prefixlen = 128;
254ebfedea0SLionel Sambuc     break;
255ebfedea0SLionel Sambuc   default:
256ebfedea0SLionel Sambuc     return NULL;
257ebfedea0SLionel Sambuc   }
258ebfedea0SLionel Sambuc   sa->sa_family = family;
259ebfedea0SLionel Sambuc #ifdef HAVE_SOCKADDR_SA_LEN
260ebfedea0SLionel Sambuc   sa->sa_len = ifa_sa_len(family, len);
261ebfedea0SLionel Sambuc #endif
262ebfedea0SLionel Sambuc   if (p){
263ebfedea0SLionel Sambuc     if (prefixlen > max_prefixlen)
264ebfedea0SLionel Sambuc       prefixlen = max_prefixlen;
265ebfedea0SLionel Sambuc     for (i=0; i<(prefixlen / 8); i++)
266ebfedea0SLionel Sambuc       *p++ = 0xff;
267ebfedea0SLionel Sambuc     c = 0xff;
268ebfedea0SLionel Sambuc     c <<= (8 - (prefixlen % 8));
269ebfedea0SLionel Sambuc     *p = c;
270ebfedea0SLionel Sambuc   }
271ebfedea0SLionel Sambuc   return sa;
272ebfedea0SLionel Sambuc }
273ebfedea0SLionel Sambuc #endif
274ebfedea0SLionel Sambuc 
275ebfedea0SLionel Sambuc /* ====================================================================== */
276ebfedea0SLionel Sambuc static int
nl_sendreq(int sd,int request,int flags,int * seq)277ebfedea0SLionel Sambuc nl_sendreq(int sd, int request, int flags, int *seq)
278ebfedea0SLionel Sambuc {
279ebfedea0SLionel Sambuc   char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
280ebfedea0SLionel Sambuc 	      NLMSG_ALIGN(sizeof(struct rtgenmsg))];
281ebfedea0SLionel Sambuc   struct sockaddr_nl nladdr;
282ebfedea0SLionel Sambuc   struct nlmsghdr *req_hdr;
283ebfedea0SLionel Sambuc   struct rtgenmsg *req_msg;
284ebfedea0SLionel Sambuc   time_t t = time(NULL);
285ebfedea0SLionel Sambuc 
286ebfedea0SLionel Sambuc   if (seq) *seq = t;
287ebfedea0SLionel Sambuc   memset(&reqbuf, 0, sizeof(reqbuf));
288ebfedea0SLionel Sambuc   req_hdr = (struct nlmsghdr *)reqbuf;
289ebfedea0SLionel Sambuc   req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
290ebfedea0SLionel Sambuc   req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
291ebfedea0SLionel Sambuc   req_hdr->nlmsg_type = request;
292ebfedea0SLionel Sambuc   req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
293ebfedea0SLionel Sambuc   req_hdr->nlmsg_pid = 0;
294ebfedea0SLionel Sambuc   req_hdr->nlmsg_seq = t;
295ebfedea0SLionel Sambuc   req_msg->rtgen_family = AF_UNSPEC;
296ebfedea0SLionel Sambuc   memset(&nladdr, 0, sizeof(nladdr));
297ebfedea0SLionel Sambuc   nladdr.nl_family = AF_NETLINK;
298ebfedea0SLionel Sambuc   return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
299ebfedea0SLionel Sambuc 		 (struct sockaddr *)&nladdr, sizeof(nladdr)));
300ebfedea0SLionel Sambuc }
301ebfedea0SLionel Sambuc 
302ebfedea0SLionel Sambuc static int
nl_recvmsg(int sd,int request,int seq,void * buf,size_t buflen,int * flags)303ebfedea0SLionel Sambuc nl_recvmsg(int sd, int request, int seq,
304ebfedea0SLionel Sambuc 	   void *buf, size_t buflen,
305ebfedea0SLionel Sambuc 	   int *flags)
306ebfedea0SLionel Sambuc {
307ebfedea0SLionel Sambuc   struct msghdr msg;
308ebfedea0SLionel Sambuc   struct iovec iov = { buf, buflen };
309ebfedea0SLionel Sambuc   struct sockaddr_nl nladdr;
310ebfedea0SLionel Sambuc   int read_len;
311ebfedea0SLionel Sambuc 
312ebfedea0SLionel Sambuc   for (;;){
313ebfedea0SLionel Sambuc     msg.msg_name = (void *)&nladdr;
314ebfedea0SLionel Sambuc     msg.msg_namelen = sizeof(nladdr);
315ebfedea0SLionel Sambuc     msg.msg_iov = &iov;
316ebfedea0SLionel Sambuc     msg.msg_iovlen = 1;
317ebfedea0SLionel Sambuc     msg.msg_control = NULL;
318ebfedea0SLionel Sambuc     msg.msg_controllen = 0;
319ebfedea0SLionel Sambuc     msg.msg_flags = 0;
320ebfedea0SLionel Sambuc     read_len = recvmsg(sd, &msg, 0);
321ebfedea0SLionel Sambuc     if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
322ebfedea0SLionel Sambuc       continue;
323ebfedea0SLionel Sambuc     if (flags) *flags = msg.msg_flags;
324ebfedea0SLionel Sambuc     break;
325ebfedea0SLionel Sambuc   }
326ebfedea0SLionel Sambuc   return read_len;
327ebfedea0SLionel Sambuc }
328ebfedea0SLionel Sambuc 
329ebfedea0SLionel Sambuc static int
nl_getmsg(int sd,int request,int seq,struct nlmsghdr ** nlhp,int * done)330ebfedea0SLionel Sambuc nl_getmsg(int sd, int request, int seq,
331ebfedea0SLionel Sambuc 	  struct nlmsghdr **nlhp,
332ebfedea0SLionel Sambuc 	  int *done)
333ebfedea0SLionel Sambuc {
334ebfedea0SLionel Sambuc   struct nlmsghdr *nh;
335ebfedea0SLionel Sambuc   size_t bufsize = 65536, lastbufsize = 0;
336ebfedea0SLionel Sambuc   void *buff = NULL;
337ebfedea0SLionel Sambuc   int result = 0, read_size;
338ebfedea0SLionel Sambuc   int msg_flags;
339ebfedea0SLionel Sambuc   pid_t pid = getpid();
340ebfedea0SLionel Sambuc   for (;;){
341ebfedea0SLionel Sambuc     void *newbuff = realloc(buff, bufsize);
342ebfedea0SLionel Sambuc     if (newbuff == NULL || bufsize < lastbufsize) {
343ebfedea0SLionel Sambuc       result = -1;
344ebfedea0SLionel Sambuc       break;
345ebfedea0SLionel Sambuc     }
346ebfedea0SLionel Sambuc     buff = newbuff;
347ebfedea0SLionel Sambuc     result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
348ebfedea0SLionel Sambuc     if (read_size < 0 || (msg_flags & MSG_TRUNC)){
349ebfedea0SLionel Sambuc       lastbufsize = bufsize;
350ebfedea0SLionel Sambuc       bufsize *= 2;
351ebfedea0SLionel Sambuc       continue;
352ebfedea0SLionel Sambuc     }
353ebfedea0SLionel Sambuc     if (read_size == 0) break;
354ebfedea0SLionel Sambuc     nh = (struct nlmsghdr *)buff;
355ebfedea0SLionel Sambuc     for (nh = (struct nlmsghdr *)buff;
356ebfedea0SLionel Sambuc 	 NLMSG_OK(nh, read_size);
357ebfedea0SLionel Sambuc 	 nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
358ebfedea0SLionel Sambuc       if (nh->nlmsg_pid != pid ||
359ebfedea0SLionel Sambuc 	  nh->nlmsg_seq != seq)
360ebfedea0SLionel Sambuc 	continue;
361ebfedea0SLionel Sambuc       if (nh->nlmsg_type == NLMSG_DONE){
362ebfedea0SLionel Sambuc 	(*done)++;
363ebfedea0SLionel Sambuc 	break; /* ok */
364ebfedea0SLionel Sambuc       }
365ebfedea0SLionel Sambuc       if (nh->nlmsg_type == NLMSG_ERROR){
366ebfedea0SLionel Sambuc 	struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
367ebfedea0SLionel Sambuc 	result = -1;
368ebfedea0SLionel Sambuc 	if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
369ebfedea0SLionel Sambuc 	  __set_errno(EIO);
370ebfedea0SLionel Sambuc 	else
371ebfedea0SLionel Sambuc 	  __set_errno(-nlerr->error);
372ebfedea0SLionel Sambuc 	break;
373ebfedea0SLionel Sambuc       }
374ebfedea0SLionel Sambuc     }
375ebfedea0SLionel Sambuc     break;
376ebfedea0SLionel Sambuc   }
377ebfedea0SLionel Sambuc   if (result < 0)
378ebfedea0SLionel Sambuc     if (buff){
379ebfedea0SLionel Sambuc       int saved_errno = errno;
380ebfedea0SLionel Sambuc       free(buff);
381ebfedea0SLionel Sambuc       __set_errno(saved_errno);
382ebfedea0SLionel Sambuc     }
383ebfedea0SLionel Sambuc   *nlhp = (struct nlmsghdr *)buff;
384ebfedea0SLionel Sambuc   return result;
385ebfedea0SLionel Sambuc }
386ebfedea0SLionel Sambuc 
387ebfedea0SLionel Sambuc static int
nl_getlist(int sd,int seq,int request,struct nlmsg_list ** nlm_list,struct nlmsg_list ** nlm_end)388ebfedea0SLionel Sambuc nl_getlist(int sd, int seq,
389ebfedea0SLionel Sambuc 	   int request,
390ebfedea0SLionel Sambuc 	   struct nlmsg_list **nlm_list,
391ebfedea0SLionel Sambuc 	   struct nlmsg_list **nlm_end)
392ebfedea0SLionel Sambuc {
393ebfedea0SLionel Sambuc   struct nlmsghdr *nlh = NULL;
394ebfedea0SLionel Sambuc   int status;
395ebfedea0SLionel Sambuc   int done = 0;
396ebfedea0SLionel Sambuc   int tries = 3;
397ebfedea0SLionel Sambuc 
398ebfedea0SLionel Sambuc  try_again:
399ebfedea0SLionel Sambuc   status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
400ebfedea0SLionel Sambuc   if (status < 0)
401ebfedea0SLionel Sambuc     return status;
402ebfedea0SLionel Sambuc   if (seq == 0)
403ebfedea0SLionel Sambuc     seq = (int)time(NULL);
404ebfedea0SLionel Sambuc   while(!done){
405ebfedea0SLionel Sambuc     struct pollfd pfd;
406ebfedea0SLionel Sambuc 
407ebfedea0SLionel Sambuc     pfd.fd = sd;
408ebfedea0SLionel Sambuc     pfd.events = POLLIN | POLLPRI;
409ebfedea0SLionel Sambuc     pfd.revents = 0;
410ebfedea0SLionel Sambuc     status = poll(&pfd, 1, 1000);
411ebfedea0SLionel Sambuc     if (status < 0)
412ebfedea0SLionel Sambuc 	return status;
413ebfedea0SLionel Sambuc     else if (status == 0) {
414ebfedea0SLionel Sambuc 	seq++;
415ebfedea0SLionel Sambuc 	if (tries-- > 0)
416ebfedea0SLionel Sambuc 	    goto try_again;
417ebfedea0SLionel Sambuc 	return -1;
418ebfedea0SLionel Sambuc     }
419ebfedea0SLionel Sambuc 
420ebfedea0SLionel Sambuc     status = nl_getmsg(sd, request, seq, &nlh, &done);
421ebfedea0SLionel Sambuc     if (status < 0)
422ebfedea0SLionel Sambuc       return status;
423ebfedea0SLionel Sambuc     if (nlh){
424ebfedea0SLionel Sambuc       struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
425ebfedea0SLionel Sambuc       if (nlm_next == NULL){
426ebfedea0SLionel Sambuc 	int saved_errno = errno;
427ebfedea0SLionel Sambuc 	free(nlh);
428ebfedea0SLionel Sambuc 	__set_errno(saved_errno);
429ebfedea0SLionel Sambuc 	status = -1;
430ebfedea0SLionel Sambuc       } else {
431ebfedea0SLionel Sambuc 	nlm_next->nlm_next = NULL;
432ebfedea0SLionel Sambuc 	nlm_next->nlh = (struct nlmsghdr *)nlh;
433ebfedea0SLionel Sambuc 	nlm_next->size = status;
434ebfedea0SLionel Sambuc 	nlm_next->seq = seq;
435ebfedea0SLionel Sambuc 	if (*nlm_list == NULL){
436ebfedea0SLionel Sambuc 	  *nlm_list = nlm_next;
437ebfedea0SLionel Sambuc 	  *nlm_end = nlm_next;
438ebfedea0SLionel Sambuc 	} else {
439ebfedea0SLionel Sambuc 	  (*nlm_end)->nlm_next = nlm_next;
440ebfedea0SLionel Sambuc 	  *nlm_end = nlm_next;
441ebfedea0SLionel Sambuc 	}
442ebfedea0SLionel Sambuc       }
443ebfedea0SLionel Sambuc     }
444ebfedea0SLionel Sambuc   }
445ebfedea0SLionel Sambuc   return status >= 0 ? seq : status;
446ebfedea0SLionel Sambuc }
447ebfedea0SLionel Sambuc 
448ebfedea0SLionel Sambuc /* ---------------------------------------------------------------------- */
449ebfedea0SLionel Sambuc static void
free_nlmsglist(struct nlmsg_list * nlm0)450ebfedea0SLionel Sambuc free_nlmsglist(struct nlmsg_list *nlm0)
451ebfedea0SLionel Sambuc {
452ebfedea0SLionel Sambuc   struct nlmsg_list *nlm, *nlm_next;
453ebfedea0SLionel Sambuc   int saved_errno;
454ebfedea0SLionel Sambuc   if (!nlm0)
455ebfedea0SLionel Sambuc     return;
456ebfedea0SLionel Sambuc   saved_errno = errno;
457ebfedea0SLionel Sambuc   for (nlm=nlm0; nlm; nlm=nlm_next){
458ebfedea0SLionel Sambuc     if (nlm->nlh)
459ebfedea0SLionel Sambuc       free(nlm->nlh);
460ebfedea0SLionel Sambuc     nlm_next=nlm->nlm_next;
461ebfedea0SLionel Sambuc     free(nlm);
462ebfedea0SLionel Sambuc   }
463ebfedea0SLionel Sambuc   __set_errno(saved_errno);
464ebfedea0SLionel Sambuc }
465ebfedea0SLionel Sambuc 
466ebfedea0SLionel Sambuc static void
free_data(void * data,void * ifdata)467ebfedea0SLionel Sambuc free_data(void *data, void *ifdata)
468ebfedea0SLionel Sambuc {
469ebfedea0SLionel Sambuc   int saved_errno = errno;
470ebfedea0SLionel Sambuc   if (data != NULL) free(data);
471ebfedea0SLionel Sambuc   if (ifdata != NULL) free(ifdata);
472ebfedea0SLionel Sambuc   __set_errno(saved_errno);
473ebfedea0SLionel Sambuc }
474ebfedea0SLionel Sambuc 
475ebfedea0SLionel Sambuc /* ---------------------------------------------------------------------- */
476ebfedea0SLionel Sambuc static void
nl_close(int sd)477ebfedea0SLionel Sambuc nl_close(int sd)
478ebfedea0SLionel Sambuc {
479ebfedea0SLionel Sambuc   int saved_errno = errno;
480ebfedea0SLionel Sambuc   if (sd >= 0) __close(sd);
481ebfedea0SLionel Sambuc   __set_errno(saved_errno);
482ebfedea0SLionel Sambuc }
483ebfedea0SLionel Sambuc 
484ebfedea0SLionel Sambuc /* ---------------------------------------------------------------------- */
485ebfedea0SLionel Sambuc static int
nl_open(void)486ebfedea0SLionel Sambuc nl_open(void)
487ebfedea0SLionel Sambuc {
488ebfedea0SLionel Sambuc   struct sockaddr_nl nladdr;
489ebfedea0SLionel Sambuc   int sd;
490ebfedea0SLionel Sambuc 
491ebfedea0SLionel Sambuc   sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
492ebfedea0SLionel Sambuc   if (sd < 0) return -1;
493ebfedea0SLionel Sambuc   memset(&nladdr, 0, sizeof(nladdr));
494ebfedea0SLionel Sambuc   nladdr.nl_family = AF_NETLINK;
495ebfedea0SLionel Sambuc   if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
496ebfedea0SLionel Sambuc     nl_close(sd);
497ebfedea0SLionel Sambuc     return -1;
498ebfedea0SLionel Sambuc   }
499ebfedea0SLionel Sambuc   return sd;
500ebfedea0SLionel Sambuc }
501ebfedea0SLionel Sambuc 
502ebfedea0SLionel Sambuc /* ====================================================================== */
503ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)504ebfedea0SLionel Sambuc rk_getifaddrs(struct ifaddrs **ifap)
505ebfedea0SLionel Sambuc {
506ebfedea0SLionel Sambuc   int sd;
507ebfedea0SLionel Sambuc   struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
508ebfedea0SLionel Sambuc   /* - - - - - - - - - - - - - - - */
509ebfedea0SLionel Sambuc   int icnt;
510ebfedea0SLionel Sambuc   size_t dlen, xlen, nlen;
511ebfedea0SLionel Sambuc   uint32_t max_ifindex = 0;
512ebfedea0SLionel Sambuc 
513ebfedea0SLionel Sambuc   pid_t pid = getpid();
514ebfedea0SLionel Sambuc   int seq;
515ebfedea0SLionel Sambuc   int result;
516ebfedea0SLionel Sambuc   int build     ; /* 0 or 1 */
517ebfedea0SLionel Sambuc 
518ebfedea0SLionel Sambuc /* ---------------------------------- */
519ebfedea0SLionel Sambuc   /* initialize */
520ebfedea0SLionel Sambuc   icnt = dlen = xlen = nlen = 0;
521ebfedea0SLionel Sambuc   nlmsg_list = nlmsg_end = NULL;
522ebfedea0SLionel Sambuc 
523ebfedea0SLionel Sambuc   if (ifap)
524ebfedea0SLionel Sambuc     *ifap = NULL;
525ebfedea0SLionel Sambuc 
526ebfedea0SLionel Sambuc /* ---------------------------------- */
527ebfedea0SLionel Sambuc   /* open socket and bind */
528ebfedea0SLionel Sambuc   sd = nl_open();
529ebfedea0SLionel Sambuc   if (sd < 0)
530ebfedea0SLionel Sambuc     return -1;
531ebfedea0SLionel Sambuc 
532ebfedea0SLionel Sambuc /* ---------------------------------- */
533ebfedea0SLionel Sambuc    /* gather info */
534ebfedea0SLionel Sambuc   if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
535ebfedea0SLionel Sambuc 			&nlmsg_list, &nlmsg_end)) < 0){
536ebfedea0SLionel Sambuc     free_nlmsglist(nlmsg_list);
537ebfedea0SLionel Sambuc     nl_close(sd);
538ebfedea0SLionel Sambuc     return -1;
539ebfedea0SLionel Sambuc   }
540ebfedea0SLionel Sambuc   if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
541ebfedea0SLionel Sambuc 			&nlmsg_list, &nlmsg_end)) < 0){
542ebfedea0SLionel Sambuc     free_nlmsglist(nlmsg_list);
543ebfedea0SLionel Sambuc     nl_close(sd);
544ebfedea0SLionel Sambuc     return -1;
545ebfedea0SLionel Sambuc   }
546ebfedea0SLionel Sambuc 
547ebfedea0SLionel Sambuc /* ---------------------------------- */
548ebfedea0SLionel Sambuc   /* Estimate size of result buffer and fill it */
549ebfedea0SLionel Sambuc   for (build=0; build<=1; build++){
550ebfedea0SLionel Sambuc     struct ifaddrs *ifl = NULL, *ifa = NULL;
551ebfedea0SLionel Sambuc     struct nlmsghdr *nlh, *nlh0;
552ebfedea0SLionel Sambuc     char *data = NULL, *xdata = NULL;
553ebfedea0SLionel Sambuc     void *ifdata = NULL;
554ebfedea0SLionel Sambuc     char *ifname = NULL, **iflist = NULL;
555ebfedea0SLionel Sambuc     uint16_t *ifflist = NULL;
556ebfedea0SLionel Sambuc     struct rtmaddr_ifamap ifamap;
557ebfedea0SLionel Sambuc 
558ebfedea0SLionel Sambuc     if (build){
559ebfedea0SLionel Sambuc       data = calloc(1,
560ebfedea0SLionel Sambuc 		    NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
561ebfedea0SLionel Sambuc 		    + dlen + xlen + nlen);
562ebfedea0SLionel Sambuc       ifa = (struct ifaddrs *)data;
563ebfedea0SLionel Sambuc       ifdata = calloc(1,
564ebfedea0SLionel Sambuc 		      NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
565ebfedea0SLionel Sambuc 		      + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
566ebfedea0SLionel Sambuc       if (ifap != NULL)
567ebfedea0SLionel Sambuc 	*ifap = (ifdata != NULL) ? ifa : NULL;
568ebfedea0SLionel Sambuc       else{
569ebfedea0SLionel Sambuc 	free_data(data, ifdata);
570ebfedea0SLionel Sambuc 	result = 0;
571ebfedea0SLionel Sambuc 	break;
572ebfedea0SLionel Sambuc       }
573ebfedea0SLionel Sambuc       if (data == NULL || ifdata == NULL){
574ebfedea0SLionel Sambuc 	free_data(data, ifdata);
575ebfedea0SLionel Sambuc 	result = -1;
576ebfedea0SLionel Sambuc 	break;
577ebfedea0SLionel Sambuc       }
578ebfedea0SLionel Sambuc       ifl = NULL;
579ebfedea0SLionel Sambuc       data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
580ebfedea0SLionel Sambuc       xdata = data + dlen;
581ebfedea0SLionel Sambuc       ifname = xdata + xlen;
582ebfedea0SLionel Sambuc       iflist = ifdata;
583ebfedea0SLionel Sambuc       ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])));
584ebfedea0SLionel Sambuc     }
585ebfedea0SLionel Sambuc 
586ebfedea0SLionel Sambuc     for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
587ebfedea0SLionel Sambuc       int nlmlen = nlm->size;
588ebfedea0SLionel Sambuc       if (!(nlh0 = nlm->nlh))
589ebfedea0SLionel Sambuc 	continue;
590ebfedea0SLionel Sambuc       for (nlh = nlh0;
591ebfedea0SLionel Sambuc 	   NLMSG_OK(nlh, nlmlen);
592ebfedea0SLionel Sambuc 	   nlh=NLMSG_NEXT(nlh,nlmlen)){
593ebfedea0SLionel Sambuc 	struct ifinfomsg *ifim = NULL;
594ebfedea0SLionel Sambuc 	struct ifaddrmsg *ifam = NULL;
595ebfedea0SLionel Sambuc 	struct rtattr *rta;
596ebfedea0SLionel Sambuc 
597ebfedea0SLionel Sambuc 	size_t nlm_struct_size = 0;
598ebfedea0SLionel Sambuc 	sa_family_t nlm_family = 0;
599ebfedea0SLionel Sambuc 	uint32_t nlm_scope = 0, nlm_index = 0;
600ebfedea0SLionel Sambuc 	size_t sockaddr_size = 0;
601ebfedea0SLionel Sambuc 	uint32_t nlm_prefixlen = 0;
602ebfedea0SLionel Sambuc 	size_t rtasize;
603ebfedea0SLionel Sambuc 
604ebfedea0SLionel Sambuc 	memset(&ifamap, 0, sizeof(ifamap));
605ebfedea0SLionel Sambuc 
606ebfedea0SLionel Sambuc 	/* check if the message is what we want */
607ebfedea0SLionel Sambuc 	if (nlh->nlmsg_pid != pid ||
608ebfedea0SLionel Sambuc 	    nlh->nlmsg_seq != nlm->seq)
609ebfedea0SLionel Sambuc 	  continue;
610ebfedea0SLionel Sambuc 	if (nlh->nlmsg_type == NLMSG_DONE){
611ebfedea0SLionel Sambuc 	  break; /* ok */
612ebfedea0SLionel Sambuc 	}
613ebfedea0SLionel Sambuc 	switch (nlh->nlmsg_type){
614ebfedea0SLionel Sambuc 	case RTM_NEWLINK:
615ebfedea0SLionel Sambuc 	  ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
616ebfedea0SLionel Sambuc 	  nlm_struct_size = sizeof(*ifim);
617ebfedea0SLionel Sambuc 	  nlm_family = ifim->ifi_family;
618ebfedea0SLionel Sambuc 	  nlm_scope = 0;
619ebfedea0SLionel Sambuc 	  nlm_index = ifim->ifi_index;
620ebfedea0SLionel Sambuc 	  nlm_prefixlen = 0;
621ebfedea0SLionel Sambuc 	  if (build)
622ebfedea0SLionel Sambuc 	    ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
623ebfedea0SLionel Sambuc 	  break;
624ebfedea0SLionel Sambuc 	case RTM_NEWADDR:
625ebfedea0SLionel Sambuc 	  ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
626ebfedea0SLionel Sambuc 	  nlm_struct_size = sizeof(*ifam);
627ebfedea0SLionel Sambuc 	  nlm_family = ifam->ifa_family;
628ebfedea0SLionel Sambuc 	  nlm_scope = ifam->ifa_scope;
629ebfedea0SLionel Sambuc 	  nlm_index = ifam->ifa_index;
630ebfedea0SLionel Sambuc 	  nlm_prefixlen = ifam->ifa_prefixlen;
631ebfedea0SLionel Sambuc 	  if (build)
632ebfedea0SLionel Sambuc 	    ifa->ifa_flags = ifflist[nlm_index];
633ebfedea0SLionel Sambuc 	  break;
634ebfedea0SLionel Sambuc 	default:
635ebfedea0SLionel Sambuc 	  continue;
636ebfedea0SLionel Sambuc 	}
637ebfedea0SLionel Sambuc 
638ebfedea0SLionel Sambuc 	if (!build){
639ebfedea0SLionel Sambuc 	  if (max_ifindex < nlm_index)
640ebfedea0SLionel Sambuc 	    max_ifindex = nlm_index;
641ebfedea0SLionel Sambuc 	} else {
642ebfedea0SLionel Sambuc 	  if (ifl != NULL)
643ebfedea0SLionel Sambuc 	    ifl->ifa_next = ifa;
644ebfedea0SLionel Sambuc 	}
645ebfedea0SLionel Sambuc 
646ebfedea0SLionel Sambuc 	rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
647ebfedea0SLionel Sambuc 	for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
648ebfedea0SLionel Sambuc 	     RTA_OK(rta, rtasize);
649ebfedea0SLionel Sambuc 	     rta = RTA_NEXT(rta, rtasize)){
650ebfedea0SLionel Sambuc 	  struct sockaddr **sap = NULL;
651ebfedea0SLionel Sambuc 	  void *rtadata = RTA_DATA(rta);
652ebfedea0SLionel Sambuc 	  size_t rtapayload = RTA_PAYLOAD(rta);
653ebfedea0SLionel Sambuc 	  socklen_t sa_len;
654ebfedea0SLionel Sambuc 
655ebfedea0SLionel Sambuc 	  switch(nlh->nlmsg_type){
656ebfedea0SLionel Sambuc 	  case RTM_NEWLINK:
657ebfedea0SLionel Sambuc 	    switch(rta->rta_type){
658ebfedea0SLionel Sambuc 	    case IFLA_ADDRESS:
659ebfedea0SLionel Sambuc 	    case IFLA_BROADCAST:
660ebfedea0SLionel Sambuc 	      if (build){
661ebfedea0SLionel Sambuc 		sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
662ebfedea0SLionel Sambuc 		*sap = (struct sockaddr *)data;
663ebfedea0SLionel Sambuc 	      }
664ebfedea0SLionel Sambuc 	      sa_len = ifa_sa_len(AF_PACKET, rtapayload);
665ebfedea0SLionel Sambuc 	      if (rta->rta_type == IFLA_ADDRESS)
666ebfedea0SLionel Sambuc 		sockaddr_size = NLMSG_ALIGN(sa_len);
667ebfedea0SLionel Sambuc 	      if (!build){
668ebfedea0SLionel Sambuc 		dlen += NLMSG_ALIGN(sa_len);
669ebfedea0SLionel Sambuc 	      } else {
670ebfedea0SLionel Sambuc 		memset(*sap, 0, sa_len);
671ebfedea0SLionel Sambuc 		ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
672ebfedea0SLionel Sambuc 		((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
673ebfedea0SLionel Sambuc 		((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
674ebfedea0SLionel Sambuc 		data += NLMSG_ALIGN(sa_len);
675ebfedea0SLionel Sambuc 	      }
676ebfedea0SLionel Sambuc 	      break;
677ebfedea0SLionel Sambuc 	    case IFLA_IFNAME:/* Name of Interface */
678ebfedea0SLionel Sambuc 	      if (!build)
679ebfedea0SLionel Sambuc 		nlen += NLMSG_ALIGN(rtapayload + 1);
680ebfedea0SLionel Sambuc 	      else{
681ebfedea0SLionel Sambuc 		ifa->ifa_name = ifname;
682ebfedea0SLionel Sambuc 		if (iflist[nlm_index] == NULL)
683ebfedea0SLionel Sambuc 		  iflist[nlm_index] = ifa->ifa_name;
684ebfedea0SLionel Sambuc 		strncpy(ifa->ifa_name, rtadata, rtapayload);
685ebfedea0SLionel Sambuc 		ifa->ifa_name[rtapayload] = '\0';
686ebfedea0SLionel Sambuc 		ifname += NLMSG_ALIGN(rtapayload + 1);
687ebfedea0SLionel Sambuc 	      }
688ebfedea0SLionel Sambuc 	      break;
689ebfedea0SLionel Sambuc 	    case IFLA_STATS:/* Statistics of Interface */
690ebfedea0SLionel Sambuc 	      if (!build)
691ebfedea0SLionel Sambuc 		xlen += NLMSG_ALIGN(rtapayload);
692ebfedea0SLionel Sambuc 	      else{
693ebfedea0SLionel Sambuc 		ifa->ifa_data = xdata;
694ebfedea0SLionel Sambuc 		memcpy(ifa->ifa_data, rtadata, rtapayload);
695ebfedea0SLionel Sambuc 		xdata += NLMSG_ALIGN(rtapayload);
696ebfedea0SLionel Sambuc 	      }
697ebfedea0SLionel Sambuc 	      break;
698ebfedea0SLionel Sambuc 	    case IFLA_UNSPEC:
699ebfedea0SLionel Sambuc 	      break;
700ebfedea0SLionel Sambuc 	    case IFLA_MTU:
701ebfedea0SLionel Sambuc 	      break;
702ebfedea0SLionel Sambuc 	    case IFLA_LINK:
703ebfedea0SLionel Sambuc 	      break;
704ebfedea0SLionel Sambuc 	    case IFLA_QDISC:
705ebfedea0SLionel Sambuc 	      break;
706ebfedea0SLionel Sambuc 	    default:
707ebfedea0SLionel Sambuc 	      break;
708ebfedea0SLionel Sambuc 	    }
709ebfedea0SLionel Sambuc 	    break;
710ebfedea0SLionel Sambuc 	  case RTM_NEWADDR:
711ebfedea0SLionel Sambuc 	    if (nlm_family == AF_PACKET) break;
712ebfedea0SLionel Sambuc 	    switch(rta->rta_type){
713ebfedea0SLionel Sambuc 	    case IFA_ADDRESS:
714ebfedea0SLionel Sambuc 		ifamap.address = rtadata;
715ebfedea0SLionel Sambuc 		ifamap.address_len = rtapayload;
716ebfedea0SLionel Sambuc 		break;
717ebfedea0SLionel Sambuc 	    case IFA_LOCAL:
718ebfedea0SLionel Sambuc 		ifamap.local = rtadata;
719ebfedea0SLionel Sambuc 		ifamap.local_len = rtapayload;
720ebfedea0SLionel Sambuc 		break;
721ebfedea0SLionel Sambuc 	    case IFA_BROADCAST:
722ebfedea0SLionel Sambuc 		ifamap.broadcast = rtadata;
723ebfedea0SLionel Sambuc 		ifamap.broadcast_len = rtapayload;
724ebfedea0SLionel Sambuc 		break;
725ebfedea0SLionel Sambuc #ifdef HAVE_IFADDRS_IFA_ANYCAST
726ebfedea0SLionel Sambuc 	    case IFA_ANYCAST:
727ebfedea0SLionel Sambuc 		ifamap.anycast = rtadata;
728ebfedea0SLionel Sambuc 		ifamap.anycast_len = rtapayload;
729ebfedea0SLionel Sambuc 		break;
730ebfedea0SLionel Sambuc #endif
731ebfedea0SLionel Sambuc 	    case IFA_LABEL:
732ebfedea0SLionel Sambuc 	      if (!build)
733ebfedea0SLionel Sambuc 		nlen += NLMSG_ALIGN(rtapayload + 1);
734ebfedea0SLionel Sambuc 	      else{
735ebfedea0SLionel Sambuc 		ifa->ifa_name = ifname;
736ebfedea0SLionel Sambuc 		if (iflist[nlm_index] == NULL)
737ebfedea0SLionel Sambuc 		  iflist[nlm_index] = ifname;
738ebfedea0SLionel Sambuc 		strncpy(ifa->ifa_name, rtadata, rtapayload);
739ebfedea0SLionel Sambuc 		ifa->ifa_name[rtapayload] = '\0';
740ebfedea0SLionel Sambuc 		ifname += NLMSG_ALIGN(rtapayload + 1);
741ebfedea0SLionel Sambuc 	      }
742ebfedea0SLionel Sambuc 	      break;
743ebfedea0SLionel Sambuc 	    case IFA_UNSPEC:
744ebfedea0SLionel Sambuc 	      break;
745ebfedea0SLionel Sambuc 	    case IFA_CACHEINFO:
746ebfedea0SLionel Sambuc 	      break;
747ebfedea0SLionel Sambuc 	    default:
748ebfedea0SLionel Sambuc 	      break;
749ebfedea0SLionel Sambuc 	    }
750ebfedea0SLionel Sambuc 	  }
751ebfedea0SLionel Sambuc 	}
752ebfedea0SLionel Sambuc 	if (nlh->nlmsg_type == RTM_NEWADDR &&
753ebfedea0SLionel Sambuc 	    nlm_family != AF_PACKET) {
754ebfedea0SLionel Sambuc 	  if (!ifamap.local) {
755ebfedea0SLionel Sambuc 	    ifamap.local = ifamap.address;
756ebfedea0SLionel Sambuc 	    ifamap.local_len = ifamap.address_len;
757ebfedea0SLionel Sambuc 	  }
758ebfedea0SLionel Sambuc 	  if (!ifamap.address) {
759ebfedea0SLionel Sambuc 	    ifamap.address = ifamap.local;
760ebfedea0SLionel Sambuc 	    ifamap.address_len = ifamap.local_len;
761ebfedea0SLionel Sambuc 	  }
762ebfedea0SLionel Sambuc 	  if (ifamap.address_len != ifamap.local_len ||
763ebfedea0SLionel Sambuc 	      (ifamap.address != NULL &&
764ebfedea0SLionel Sambuc 	       memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
765ebfedea0SLionel Sambuc 	    /* p2p; address is peer and local is ours */
766ebfedea0SLionel Sambuc 	    ifamap.broadcast = ifamap.address;
767ebfedea0SLionel Sambuc 	    ifamap.broadcast_len = ifamap.address_len;
768ebfedea0SLionel Sambuc 	    ifamap.address = ifamap.local;
769ebfedea0SLionel Sambuc 	    ifamap.address_len = ifamap.local_len;
770ebfedea0SLionel Sambuc 	  }
771ebfedea0SLionel Sambuc 	  if (ifamap.address) {
772ebfedea0SLionel Sambuc #ifndef IFA_NETMASK
773ebfedea0SLionel Sambuc 	    sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
774ebfedea0SLionel Sambuc #endif
775ebfedea0SLionel Sambuc 	    if (!build)
776ebfedea0SLionel Sambuc 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
777ebfedea0SLionel Sambuc 	    else {
778ebfedea0SLionel Sambuc 	      ifa->ifa_addr = (struct sockaddr *)data;
779ebfedea0SLionel Sambuc 	      ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
780ebfedea0SLionel Sambuc 				nlm_scope, nlm_index);
781ebfedea0SLionel Sambuc 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
782ebfedea0SLionel Sambuc 	    }
783ebfedea0SLionel Sambuc 	  }
784ebfedea0SLionel Sambuc #ifdef IFA_NETMASK
785ebfedea0SLionel Sambuc 	  if (ifamap.netmask) {
786ebfedea0SLionel Sambuc 	    if (!build)
787ebfedea0SLionel Sambuc 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
788ebfedea0SLionel Sambuc 	    else {
789ebfedea0SLionel Sambuc 	      ifa->ifa_netmask = (struct sockaddr *)data;
790ebfedea0SLionel Sambuc 	      ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
791ebfedea0SLionel Sambuc 				nlm_scope, nlm_index);
792ebfedea0SLionel Sambuc 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
793ebfedea0SLionel Sambuc 	    }
794ebfedea0SLionel Sambuc 	  }
795ebfedea0SLionel Sambuc #endif
796ebfedea0SLionel Sambuc 	  if (ifamap.broadcast) {
797ebfedea0SLionel Sambuc 	    if (!build)
798ebfedea0SLionel Sambuc 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
799ebfedea0SLionel Sambuc 	    else {
800ebfedea0SLionel Sambuc 	      ifa->ifa_broadaddr = (struct sockaddr *)data;
801ebfedea0SLionel Sambuc 	      ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
802ebfedea0SLionel Sambuc 				nlm_scope, nlm_index);
803ebfedea0SLionel Sambuc 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
804ebfedea0SLionel Sambuc 	    }
805ebfedea0SLionel Sambuc 	  }
806ebfedea0SLionel Sambuc #ifdef HAVE_IFADDRS_IFA_ANYCAST
807ebfedea0SLionel Sambuc 	  if (ifamap.anycast) {
808ebfedea0SLionel Sambuc 	    if (!build)
809ebfedea0SLionel Sambuc 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
810ebfedea0SLionel Sambuc 	    else {
811ebfedea0SLionel Sambuc 	      ifa->ifa_anycast = (struct sockaddr *)data;
812ebfedea0SLionel Sambuc 	      ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
813ebfedea0SLionel Sambuc 				nlm_scope, nlm_index);
814ebfedea0SLionel Sambuc 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
815ebfedea0SLionel Sambuc 	    }
816ebfedea0SLionel Sambuc 	  }
817ebfedea0SLionel Sambuc #endif
818ebfedea0SLionel Sambuc 	}
819ebfedea0SLionel Sambuc 	if (!build){
820ebfedea0SLionel Sambuc #ifndef IFA_NETMASK
821ebfedea0SLionel Sambuc 	  dlen += sockaddr_size;
822ebfedea0SLionel Sambuc #endif
823ebfedea0SLionel Sambuc 	  icnt++;
824ebfedea0SLionel Sambuc 	} else {
825ebfedea0SLionel Sambuc 	  if (ifa->ifa_name == NULL)
826ebfedea0SLionel Sambuc 	    ifa->ifa_name = iflist[nlm_index];
827ebfedea0SLionel Sambuc #ifndef IFA_NETMASK
828ebfedea0SLionel Sambuc 	  if (ifa->ifa_addr &&
829ebfedea0SLionel Sambuc 	      ifa->ifa_addr->sa_family != AF_UNSPEC &&
830ebfedea0SLionel Sambuc 	      ifa->ifa_addr->sa_family != AF_PACKET){
831ebfedea0SLionel Sambuc 	    ifa->ifa_netmask = (struct sockaddr *)data;
832ebfedea0SLionel Sambuc 	    ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
833ebfedea0SLionel Sambuc 	  }
834ebfedea0SLionel Sambuc 	  data += sockaddr_size;
835ebfedea0SLionel Sambuc #endif
836ebfedea0SLionel Sambuc 	  ifl = ifa++;
837ebfedea0SLionel Sambuc 	}
838ebfedea0SLionel Sambuc       }
839ebfedea0SLionel Sambuc     }
840ebfedea0SLionel Sambuc     if (!build){
841ebfedea0SLionel Sambuc       if (icnt == 0 && (dlen + nlen + xlen == 0)){
842ebfedea0SLionel Sambuc 	if (ifap != NULL)
843ebfedea0SLionel Sambuc 	  *ifap = NULL;
844ebfedea0SLionel Sambuc 	break; /* cannot found any addresses */
845ebfedea0SLionel Sambuc       }
846ebfedea0SLionel Sambuc     }
847ebfedea0SLionel Sambuc     else
848ebfedea0SLionel Sambuc       free_data(NULL, ifdata);
849ebfedea0SLionel Sambuc   }
850ebfedea0SLionel Sambuc 
851ebfedea0SLionel Sambuc /* ---------------------------------- */
852ebfedea0SLionel Sambuc   /* Finalize */
853ebfedea0SLionel Sambuc   free_nlmsglist(nlmsg_list);
854ebfedea0SLionel Sambuc   nl_close(sd);
855ebfedea0SLionel Sambuc   return 0;
856ebfedea0SLionel Sambuc }
857ebfedea0SLionel Sambuc 
858ebfedea0SLionel Sambuc void ROKEN_LIB_FUNCTION
rk_freeifaddrs(struct ifaddrs * ifp)859ebfedea0SLionel Sambuc rk_freeifaddrs(struct ifaddrs *ifp)
860ebfedea0SLionel Sambuc {
861ebfedea0SLionel Sambuc     /* AF_NETLINK method uses a single allocation for all interfaces */
862ebfedea0SLionel Sambuc     free(ifp);
863ebfedea0SLionel Sambuc }
864ebfedea0SLionel Sambuc 
865ebfedea0SLionel Sambuc #else /* !AF_NETLINK */
866ebfedea0SLionel Sambuc 
867ebfedea0SLionel Sambuc /*
868ebfedea0SLionel Sambuc  * The generic SIOCGIFCONF version.
869ebfedea0SLionel Sambuc  */
870ebfedea0SLionel Sambuc 
871ebfedea0SLionel Sambuc static int
getifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)872ebfedea0SLionel Sambuc getifaddrs2(struct ifaddrs **ifap,
873ebfedea0SLionel Sambuc 	    int af, int siocgifconf, int siocgifflags,
874ebfedea0SLionel Sambuc 	    size_t ifreq_sz)
875ebfedea0SLionel Sambuc {
876ebfedea0SLionel Sambuc     int ret;
877ebfedea0SLionel Sambuc     int fd;
878ebfedea0SLionel Sambuc     size_t buf_size;
879ebfedea0SLionel Sambuc     char *buf;
880ebfedea0SLionel Sambuc     struct ifconf ifconf;
881ebfedea0SLionel Sambuc     char *p;
882ebfedea0SLionel Sambuc     size_t sz;
883ebfedea0SLionel Sambuc     struct sockaddr sa_zero;
884ebfedea0SLionel Sambuc     struct ifreq *ifr;
885ebfedea0SLionel Sambuc     struct ifaddrs *start = NULL, **end = &start;
886ebfedea0SLionel Sambuc 
887ebfedea0SLionel Sambuc     buf = NULL;
888ebfedea0SLionel Sambuc 
889ebfedea0SLionel Sambuc     memset (&sa_zero, 0, sizeof(sa_zero));
890ebfedea0SLionel Sambuc     fd = socket(af, SOCK_DGRAM, 0);
891ebfedea0SLionel Sambuc     if (fd < 0)
892ebfedea0SLionel Sambuc 	return -1;
893ebfedea0SLionel Sambuc 
894ebfedea0SLionel Sambuc     buf_size = 8192;
895ebfedea0SLionel Sambuc     for (;;) {
896ebfedea0SLionel Sambuc 	buf = calloc(1, buf_size);
897ebfedea0SLionel Sambuc 	if (buf == NULL) {
898ebfedea0SLionel Sambuc 	    ret = ENOMEM;
899ebfedea0SLionel Sambuc 	    goto error_out;
900ebfedea0SLionel Sambuc 	}
901ebfedea0SLionel Sambuc 	ifconf.ifc_len = buf_size;
902ebfedea0SLionel Sambuc 	ifconf.ifc_buf = buf;
903ebfedea0SLionel Sambuc 
904ebfedea0SLionel Sambuc 	/*
905ebfedea0SLionel Sambuc 	 * Solaris returns EINVAL when the buffer is too small.
906ebfedea0SLionel Sambuc 	 */
907ebfedea0SLionel Sambuc 	if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
908ebfedea0SLionel Sambuc 	    ret = errno;
909ebfedea0SLionel Sambuc 	    goto error_out;
910ebfedea0SLionel Sambuc 	}
911ebfedea0SLionel Sambuc 	/*
912ebfedea0SLionel Sambuc 	 * Can the difference between a full and a overfull buf
913ebfedea0SLionel Sambuc 	 * be determined?
914ebfedea0SLionel Sambuc 	 */
915ebfedea0SLionel Sambuc 
916ebfedea0SLionel Sambuc 	if (ifconf.ifc_len < buf_size)
917ebfedea0SLionel Sambuc 	    break;
918ebfedea0SLionel Sambuc 	free (buf);
919ebfedea0SLionel Sambuc 	buf_size *= 2;
920ebfedea0SLionel Sambuc     }
921ebfedea0SLionel Sambuc 
922ebfedea0SLionel Sambuc     for (p = ifconf.ifc_buf;
923ebfedea0SLionel Sambuc 	 p < ifconf.ifc_buf + ifconf.ifc_len;
924ebfedea0SLionel Sambuc 	 p += sz) {
925ebfedea0SLionel Sambuc 	struct ifreq ifreq;
926ebfedea0SLionel Sambuc 	struct sockaddr *sa;
927ebfedea0SLionel Sambuc 	size_t salen;
928ebfedea0SLionel Sambuc 
929ebfedea0SLionel Sambuc 	ifr = (struct ifreq *)p;
930ebfedea0SLionel Sambuc 	sa  = &ifr->ifr_addr;
931ebfedea0SLionel Sambuc 
932ebfedea0SLionel Sambuc 	sz = ifreq_sz;
933ebfedea0SLionel Sambuc 	salen = sizeof(struct sockaddr);
934ebfedea0SLionel Sambuc #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
935ebfedea0SLionel Sambuc 	salen = sa->sa_len;
936ebfedea0SLionel Sambuc 	sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
937ebfedea0SLionel Sambuc #endif
938ebfedea0SLionel Sambuc #ifdef SA_LEN
939ebfedea0SLionel Sambuc 	salen = SA_LEN(sa);
940ebfedea0SLionel Sambuc 	sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
941ebfedea0SLionel Sambuc #endif
942ebfedea0SLionel Sambuc 	memset (&ifreq, 0, sizeof(ifreq));
943ebfedea0SLionel Sambuc 	memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
944ebfedea0SLionel Sambuc 
945ebfedea0SLionel Sambuc 	if (ioctl(fd, siocgifflags, &ifreq) < 0) {
946ebfedea0SLionel Sambuc 	    ret = errno;
947ebfedea0SLionel Sambuc 	    goto error_out;
948ebfedea0SLionel Sambuc 	}
949ebfedea0SLionel Sambuc 
950ebfedea0SLionel Sambuc 	*end = malloc(sizeof(**end));
951ebfedea0SLionel Sambuc 	if (*end == NULL) {
952ebfedea0SLionel Sambuc 	    ret = ENOMEM;
953ebfedea0SLionel Sambuc 	    goto error_out;
954ebfedea0SLionel Sambuc 	}
955ebfedea0SLionel Sambuc 
956ebfedea0SLionel Sambuc 	(*end)->ifa_next = NULL;
957ebfedea0SLionel Sambuc 	(*end)->ifa_name = strdup(ifr->ifr_name);
958ebfedea0SLionel Sambuc 	if ((*end)->ifa_name == NULL) {
959ebfedea0SLionel Sambuc 	    ret = ENOMEM;
960ebfedea0SLionel Sambuc 	    goto error_out;
961ebfedea0SLionel Sambuc 	}
962ebfedea0SLionel Sambuc 	(*end)->ifa_flags = ifreq.ifr_flags;
963ebfedea0SLionel Sambuc 	(*end)->ifa_addr = malloc(salen);
964ebfedea0SLionel Sambuc 	if ((*end)->ifa_addr == NULL) {
965ebfedea0SLionel Sambuc 	    ret = ENOMEM;
966ebfedea0SLionel Sambuc 	    goto error_out;
967ebfedea0SLionel Sambuc 	}
968ebfedea0SLionel Sambuc 	memcpy((*end)->ifa_addr, sa, salen);
969ebfedea0SLionel Sambuc 	(*end)->ifa_netmask = NULL;
970ebfedea0SLionel Sambuc 
971ebfedea0SLionel Sambuc #if 0
972ebfedea0SLionel Sambuc 	/* fix these when we actually need them */
973ebfedea0SLionel Sambuc 	if(ifreq.ifr_flags & IFF_BROADCAST) {
974ebfedea0SLionel Sambuc 	    (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
975ebfedea0SLionel Sambuc 	    if ((*end)->ifa_broadaddr == NULL) {
976ebfedea0SLionel Sambuc 		ret = ENOMEM;
977ebfedea0SLionel Sambuc 		goto error_out;
978ebfedea0SLionel Sambuc 	    }
979ebfedea0SLionel Sambuc 	    memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
980ebfedea0SLionel Sambuc 		   sizeof(ifr->ifr_broadaddr));
981ebfedea0SLionel Sambuc 	} else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
982ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
983ebfedea0SLionel Sambuc 	    if ((*end)->ifa_dstaddr == NULL) {
984ebfedea0SLionel Sambuc 		ret = ENOMEM;
985ebfedea0SLionel Sambuc 		goto error_out;
986ebfedea0SLionel Sambuc 	    }
987ebfedea0SLionel Sambuc 	    memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
988ebfedea0SLionel Sambuc 		   sizeof(ifr->ifr_dstaddr));
989ebfedea0SLionel Sambuc 	} else
990ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = NULL;
991ebfedea0SLionel Sambuc #else
992ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = NULL;
993ebfedea0SLionel Sambuc #endif
994ebfedea0SLionel Sambuc 
995ebfedea0SLionel Sambuc 	(*end)->ifa_data = NULL;
996ebfedea0SLionel Sambuc 
997ebfedea0SLionel Sambuc 	end = &(*end)->ifa_next;
998ebfedea0SLionel Sambuc 
999ebfedea0SLionel Sambuc     }
1000ebfedea0SLionel Sambuc     *ifap = start;
1001ebfedea0SLionel Sambuc     close(fd);
1002ebfedea0SLionel Sambuc     free(buf);
1003ebfedea0SLionel Sambuc     return 0;
1004ebfedea0SLionel Sambuc   error_out:
1005ebfedea0SLionel Sambuc     rk_freeifaddrs(start);
1006ebfedea0SLionel Sambuc     close(fd);
1007ebfedea0SLionel Sambuc     free(buf);
1008ebfedea0SLionel Sambuc     errno = ret;
1009ebfedea0SLionel Sambuc     return -1;
1010ebfedea0SLionel Sambuc }
1011ebfedea0SLionel Sambuc 
1012ebfedea0SLionel Sambuc #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1013ebfedea0SLionel Sambuc static int
getlifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)1014ebfedea0SLionel Sambuc getlifaddrs2(struct ifaddrs **ifap,
1015ebfedea0SLionel Sambuc 	     int af, int siocgifconf, int siocgifflags,
1016ebfedea0SLionel Sambuc 	     size_t ifreq_sz)
1017ebfedea0SLionel Sambuc {
1018ebfedea0SLionel Sambuc     int ret;
1019ebfedea0SLionel Sambuc     int fd;
1020ebfedea0SLionel Sambuc     size_t buf_size;
1021ebfedea0SLionel Sambuc     char *buf;
1022ebfedea0SLionel Sambuc     struct lifconf ifconf;
1023ebfedea0SLionel Sambuc     char *p;
1024ebfedea0SLionel Sambuc     size_t sz;
1025ebfedea0SLionel Sambuc     struct sockaddr sa_zero;
1026ebfedea0SLionel Sambuc     struct lifreq *ifr;
1027ebfedea0SLionel Sambuc     struct ifaddrs *start = NULL, **end = &start;
1028ebfedea0SLionel Sambuc 
1029ebfedea0SLionel Sambuc     buf = NULL;
1030ebfedea0SLionel Sambuc 
1031ebfedea0SLionel Sambuc     memset (&sa_zero, 0, sizeof(sa_zero));
1032ebfedea0SLionel Sambuc     fd = socket(af, SOCK_DGRAM, 0);
1033ebfedea0SLionel Sambuc     if (fd < 0)
1034ebfedea0SLionel Sambuc 	return -1;
1035ebfedea0SLionel Sambuc 
1036ebfedea0SLionel Sambuc     buf_size = 8192;
1037ebfedea0SLionel Sambuc     for (;;) {
1038ebfedea0SLionel Sambuc 	buf = calloc(1, buf_size);
1039ebfedea0SLionel Sambuc 	if (buf == NULL) {
1040ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1041ebfedea0SLionel Sambuc 	    goto error_out;
1042ebfedea0SLionel Sambuc 	}
1043ebfedea0SLionel Sambuc #ifndef __hpux
1044ebfedea0SLionel Sambuc 	ifconf.lifc_family = af;
1045ebfedea0SLionel Sambuc 	ifconf.lifc_flags  = 0;
1046ebfedea0SLionel Sambuc #endif
1047ebfedea0SLionel Sambuc 	ifconf.lifc_len    = buf_size;
1048ebfedea0SLionel Sambuc 	ifconf.lifc_buf    = buf;
1049ebfedea0SLionel Sambuc 
1050ebfedea0SLionel Sambuc 	/*
1051ebfedea0SLionel Sambuc 	 * Solaris returns EINVAL when the buffer is too small.
1052ebfedea0SLionel Sambuc 	 */
1053ebfedea0SLionel Sambuc 	if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
1054ebfedea0SLionel Sambuc 	    ret = errno;
1055ebfedea0SLionel Sambuc 	    goto error_out;
1056ebfedea0SLionel Sambuc 	}
1057ebfedea0SLionel Sambuc 	/*
1058ebfedea0SLionel Sambuc 	 * Can the difference between a full and a overfull buf
1059ebfedea0SLionel Sambuc 	 * be determined?
1060ebfedea0SLionel Sambuc 	 */
1061ebfedea0SLionel Sambuc 
1062ebfedea0SLionel Sambuc 	if (ifconf.lifc_len < buf_size)
1063ebfedea0SLionel Sambuc 	    break;
1064ebfedea0SLionel Sambuc 	free (buf);
1065ebfedea0SLionel Sambuc 	buf_size *= 2;
1066ebfedea0SLionel Sambuc     }
1067ebfedea0SLionel Sambuc 
1068ebfedea0SLionel Sambuc     for (p = ifconf.lifc_buf;
1069ebfedea0SLionel Sambuc 	 p < ifconf.lifc_buf + ifconf.lifc_len;
1070ebfedea0SLionel Sambuc 	 p += sz) {
1071ebfedea0SLionel Sambuc 	struct lifreq ifreq;
1072ebfedea0SLionel Sambuc 	struct sockaddr_storage *sa;
1073ebfedea0SLionel Sambuc 	size_t salen;
1074ebfedea0SLionel Sambuc 
1075ebfedea0SLionel Sambuc 	ifr = (struct lifreq *)p;
1076ebfedea0SLionel Sambuc 	sa  = &ifr->lifr_addr;
1077ebfedea0SLionel Sambuc 
1078ebfedea0SLionel Sambuc 	sz = ifreq_sz;
1079ebfedea0SLionel Sambuc 	salen = sizeof(struct sockaddr_storage);
1080ebfedea0SLionel Sambuc #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1081ebfedea0SLionel Sambuc 	salen = sa->sa_len;
1082ebfedea0SLionel Sambuc 	sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
1083ebfedea0SLionel Sambuc #endif
1084ebfedea0SLionel Sambuc #ifdef SA_LEN
1085ebfedea0SLionel Sambuc 	salen = SA_LEN(sa);
1086ebfedea0SLionel Sambuc 	sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
1087ebfedea0SLionel Sambuc #endif
1088ebfedea0SLionel Sambuc 	memset (&ifreq, 0, sizeof(ifreq));
1089ebfedea0SLionel Sambuc 	memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name));
1090ebfedea0SLionel Sambuc 
1091ebfedea0SLionel Sambuc 	if (ioctl(fd, siocgifflags, &ifreq) < 0) {
1092ebfedea0SLionel Sambuc 	    ret = errno;
1093ebfedea0SLionel Sambuc 	    goto error_out;
1094ebfedea0SLionel Sambuc 	}
1095ebfedea0SLionel Sambuc 
1096ebfedea0SLionel Sambuc 	*end = malloc(sizeof(**end));
1097ebfedea0SLionel Sambuc 	if (*end == NULL) {
1098ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1099ebfedea0SLionel Sambuc 	    goto error_out;
1100ebfedea0SLionel Sambuc 	}
1101ebfedea0SLionel Sambuc 
1102ebfedea0SLionel Sambuc 	(*end)->ifa_next = NULL;
1103ebfedea0SLionel Sambuc 	(*end)->ifa_name = strdup(ifr->lifr_name);
1104ebfedea0SLionel Sambuc 	if ((*end)->ifa_name == NULL) {
1105ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1106ebfedea0SLionel Sambuc 	    goto error_out;
1107ebfedea0SLionel Sambuc 	}
1108ebfedea0SLionel Sambuc 	(*end)->ifa_flags = ifreq.lifr_flags;
1109ebfedea0SLionel Sambuc 	(*end)->ifa_addr = malloc(salen);
1110ebfedea0SLionel Sambuc 	if ((*end)->ifa_addr == NULL) {
1111ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1112ebfedea0SLionel Sambuc 	    goto error_out;
1113ebfedea0SLionel Sambuc 	}
1114ebfedea0SLionel Sambuc 	memcpy((*end)->ifa_addr, sa, salen);
1115ebfedea0SLionel Sambuc 	(*end)->ifa_netmask = NULL;
1116ebfedea0SLionel Sambuc 
1117ebfedea0SLionel Sambuc #if 0
1118ebfedea0SLionel Sambuc 	/* fix these when we actually need them */
1119ebfedea0SLionel Sambuc 	if(ifreq.ifr_flags & IFF_BROADCAST) {
1120ebfedea0SLionel Sambuc 	    (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
1121ebfedea0SLionel Sambuc 	    if ((*end)->ifa_broadaddr == NULL) {
1122ebfedea0SLionel Sambuc 		ret = ENOMEM;
1123ebfedea0SLionel Sambuc 		goto error_out;
1124ebfedea0SLionel Sambuc 	    }
1125ebfedea0SLionel Sambuc 	    memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
1126ebfedea0SLionel Sambuc 		   sizeof(ifr->ifr_broadaddr));
1127ebfedea0SLionel Sambuc 	} else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
1128ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
1129ebfedea0SLionel Sambuc 	    if ((*end)->ifa_dstaddr == NULL) {
1130ebfedea0SLionel Sambuc 		ret = ENOMEM;
1131ebfedea0SLionel Sambuc 		goto error_out;
1132ebfedea0SLionel Sambuc 	    }
1133ebfedea0SLionel Sambuc 	    memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
1134ebfedea0SLionel Sambuc 		   sizeof(ifr->ifr_dstaddr));
1135ebfedea0SLionel Sambuc 	} else
1136ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = NULL;
1137ebfedea0SLionel Sambuc #else
1138ebfedea0SLionel Sambuc 	    (*end)->ifa_dstaddr = NULL;
1139ebfedea0SLionel Sambuc #endif
1140ebfedea0SLionel Sambuc 
1141ebfedea0SLionel Sambuc 	(*end)->ifa_data = NULL;
1142ebfedea0SLionel Sambuc 
1143ebfedea0SLionel Sambuc 	end = &(*end)->ifa_next;
1144ebfedea0SLionel Sambuc 
1145ebfedea0SLionel Sambuc     }
1146ebfedea0SLionel Sambuc     *ifap = start;
1147ebfedea0SLionel Sambuc     close(fd);
1148ebfedea0SLionel Sambuc     free(buf);
1149ebfedea0SLionel Sambuc     return 0;
1150ebfedea0SLionel Sambuc   error_out:
1151ebfedea0SLionel Sambuc     rk_freeifaddrs(start);
1152ebfedea0SLionel Sambuc     close(fd);
1153ebfedea0SLionel Sambuc     free(buf);
1154ebfedea0SLionel Sambuc     errno = ret;
1155ebfedea0SLionel Sambuc     return -1;
1156ebfedea0SLionel Sambuc }
1157ebfedea0SLionel Sambuc #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
1158ebfedea0SLionel Sambuc 
1159ebfedea0SLionel Sambuc /**
1160ebfedea0SLionel Sambuc  * Join two struct ifaddrs lists by appending supp to base.
1161ebfedea0SLionel Sambuc  * Either may be NULL. The new list head (usually base) will be
1162ebfedea0SLionel Sambuc  * returned.
1163ebfedea0SLionel Sambuc  */
1164ebfedea0SLionel Sambuc static struct ifaddrs *
append_ifaddrs(struct ifaddrs * base,struct ifaddrs * supp)1165ebfedea0SLionel Sambuc append_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) {
1166ebfedea0SLionel Sambuc     if (!base)
1167ebfedea0SLionel Sambuc 	return supp;
1168ebfedea0SLionel Sambuc 
1169ebfedea0SLionel Sambuc     if (!supp)
1170ebfedea0SLionel Sambuc 	return base;
1171ebfedea0SLionel Sambuc 
1172ebfedea0SLionel Sambuc     while (base->ifa_next)
1173ebfedea0SLionel Sambuc 	base = base->ifa_next;
1174ebfedea0SLionel Sambuc 
1175ebfedea0SLionel Sambuc     base->ifa_next = supp;
1176ebfedea0SLionel Sambuc 
1177ebfedea0SLionel Sambuc     return base;
1178ebfedea0SLionel Sambuc }
1179ebfedea0SLionel Sambuc 
1180ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)1181ebfedea0SLionel Sambuc rk_getifaddrs(struct ifaddrs **ifap)
1182ebfedea0SLionel Sambuc {
1183ebfedea0SLionel Sambuc     int ret = -1;
1184ebfedea0SLionel Sambuc     errno = ENXIO;
1185ebfedea0SLionel Sambuc #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
1186ebfedea0SLionel Sambuc     if (ret)
1187ebfedea0SLionel Sambuc 	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
1188ebfedea0SLionel Sambuc 			   sizeof(struct in6_ifreq));
1189ebfedea0SLionel Sambuc #endif
1190ebfedea0SLionel Sambuc #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1191ebfedea0SLionel Sambuc     /* Do IPv6 and IPv4 queries separately then join the result.
1192ebfedea0SLionel Sambuc      *
1193ebfedea0SLionel Sambuc      * HP-UX only returns IPv6 addresses using SIOCGLIFCONF,
1194ebfedea0SLionel Sambuc      * SIOCGIFCONF has to be used for IPv4 addresses. The result is then
1195ebfedea0SLionel Sambuc      * merged.
1196ebfedea0SLionel Sambuc      *
1197ebfedea0SLionel Sambuc      * Solaris needs particular care, because a SIOCGLIFCONF lookup using
1198ebfedea0SLionel Sambuc      * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just
1199ebfedea0SLionel Sambuc      * do them separately the same as for HP-UX. See
1200ebfedea0SLionel Sambuc      * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73
1201ebfedea0SLionel Sambuc      */
1202ebfedea0SLionel Sambuc     if (ret) {
1203ebfedea0SLionel Sambuc 	int v6err, v4err;
1204ebfedea0SLionel Sambuc 	struct ifaddrs *v6addrs, *v4addrs;
1205ebfedea0SLionel Sambuc 
1206ebfedea0SLionel Sambuc 	v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS,
1207ebfedea0SLionel Sambuc 			    sizeof(struct lifreq));
1208ebfedea0SLionel Sambuc 	v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1209ebfedea0SLionel Sambuc 			    sizeof(struct ifreq));
1210ebfedea0SLionel Sambuc 	if (v6err)
1211ebfedea0SLionel Sambuc 	    v6addrs = NULL;
1212ebfedea0SLionel Sambuc 	if (v4err)
1213ebfedea0SLionel Sambuc 	    v4addrs = NULL;
1214ebfedea0SLionel Sambuc 
1215ebfedea0SLionel Sambuc 	if (v6addrs) {
1216ebfedea0SLionel Sambuc 	    if (v4addrs)
1217ebfedea0SLionel Sambuc 		*ifap = append_ifaddrs(v6addrs, v4addrs);
1218ebfedea0SLionel Sambuc 	    else
1219ebfedea0SLionel Sambuc 		*ifap = v6addrs;
1220ebfedea0SLionel Sambuc 	} else if (v4addrs) {
1221ebfedea0SLionel Sambuc 	    *ifap = v4addrs;
1222ebfedea0SLionel Sambuc 	} else {
1223ebfedea0SLionel Sambuc 	    *ifap = NULL;
1224ebfedea0SLionel Sambuc 	}
1225ebfedea0SLionel Sambuc 
1226ebfedea0SLionel Sambuc 	ret = (v6err || v4err) ? -1 : 0;
1227ebfedea0SLionel Sambuc     }
1228ebfedea0SLionel Sambuc #endif
1229ebfedea0SLionel Sambuc #if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
1230ebfedea0SLionel Sambuc     if (ret)
1231ebfedea0SLionel Sambuc 	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
1232ebfedea0SLionel Sambuc 			   sizeof(struct ifreq));
1233ebfedea0SLionel Sambuc #endif
1234ebfedea0SLionel Sambuc #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
1235ebfedea0SLionel Sambuc     if (ret)
1236ebfedea0SLionel Sambuc 	ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1237ebfedea0SLionel Sambuc 			   sizeof(struct ifreq));
1238ebfedea0SLionel Sambuc #endif
1239ebfedea0SLionel Sambuc     return ret;
1240ebfedea0SLionel Sambuc }
1241ebfedea0SLionel Sambuc 
1242ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_freeifaddrs(struct ifaddrs * ifp)1243ebfedea0SLionel Sambuc rk_freeifaddrs(struct ifaddrs *ifp)
1244ebfedea0SLionel Sambuc {
1245ebfedea0SLionel Sambuc     struct ifaddrs *p, *q;
1246ebfedea0SLionel Sambuc 
1247ebfedea0SLionel Sambuc     for(p = ifp; p; ) {
1248ebfedea0SLionel Sambuc 	free(p->ifa_name);
1249ebfedea0SLionel Sambuc 	if(p->ifa_addr)
1250ebfedea0SLionel Sambuc 	    free(p->ifa_addr);
1251ebfedea0SLionel Sambuc 	if(p->ifa_dstaddr)
1252ebfedea0SLionel Sambuc 	    free(p->ifa_dstaddr);
1253ebfedea0SLionel Sambuc 	if(p->ifa_netmask)
1254ebfedea0SLionel Sambuc 	    free(p->ifa_netmask);
1255ebfedea0SLionel Sambuc 	if(p->ifa_data)
1256ebfedea0SLionel Sambuc 	    free(p->ifa_data);
1257ebfedea0SLionel Sambuc 	q = p;
1258ebfedea0SLionel Sambuc 	p = p->ifa_next;
1259ebfedea0SLionel Sambuc 	free(q);
1260ebfedea0SLionel Sambuc     }
1261ebfedea0SLionel Sambuc }
1262ebfedea0SLionel Sambuc 
1263ebfedea0SLionel Sambuc #endif /* !AF_NETLINK */
1264ebfedea0SLionel Sambuc 
1265ebfedea0SLionel Sambuc #ifdef TEST
1266ebfedea0SLionel Sambuc 
1267ebfedea0SLionel Sambuc void
print_addr(const char * s,struct sockaddr * sa)1268ebfedea0SLionel Sambuc print_addr(const char *s, struct sockaddr *sa)
1269ebfedea0SLionel Sambuc {
1270ebfedea0SLionel Sambuc     int i;
1271ebfedea0SLionel Sambuc     printf("  %s=%d/", s, sa->sa_family);
1272ebfedea0SLionel Sambuc #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1273ebfedea0SLionel Sambuc     for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
1274ebfedea0SLionel Sambuc 	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1275ebfedea0SLionel Sambuc #else
1276ebfedea0SLionel Sambuc     for(i = 0; i < sizeof(sa->sa_data); i++)
1277ebfedea0SLionel Sambuc 	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1278ebfedea0SLionel Sambuc #endif
1279ebfedea0SLionel Sambuc     printf("\n");
1280ebfedea0SLionel Sambuc }
1281ebfedea0SLionel Sambuc 
1282ebfedea0SLionel Sambuc void
print_ifaddrs(struct ifaddrs * x)1283ebfedea0SLionel Sambuc print_ifaddrs(struct ifaddrs *x)
1284ebfedea0SLionel Sambuc {
1285ebfedea0SLionel Sambuc     struct ifaddrs *p;
1286ebfedea0SLionel Sambuc 
1287ebfedea0SLionel Sambuc     for(p = x; p; p = p->ifa_next) {
1288ebfedea0SLionel Sambuc 	printf("%s\n", p->ifa_name);
1289ebfedea0SLionel Sambuc 	printf("  flags=%x\n", p->ifa_flags);
1290ebfedea0SLionel Sambuc 	if(p->ifa_addr)
1291ebfedea0SLionel Sambuc 	    print_addr("addr", p->ifa_addr);
1292ebfedea0SLionel Sambuc 	if(p->ifa_dstaddr)
1293ebfedea0SLionel Sambuc 	    print_addr("dstaddr", p->ifa_dstaddr);
1294ebfedea0SLionel Sambuc 	if(p->ifa_netmask)
1295ebfedea0SLionel Sambuc 	    print_addr("netmask", p->ifa_netmask);
1296ebfedea0SLionel Sambuc 	printf("  %p\n", p->ifa_data);
1297ebfedea0SLionel Sambuc     }
1298ebfedea0SLionel Sambuc }
1299ebfedea0SLionel Sambuc 
1300ebfedea0SLionel Sambuc int
main()1301ebfedea0SLionel Sambuc main()
1302ebfedea0SLionel Sambuc {
1303ebfedea0SLionel Sambuc     struct ifaddrs *a = NULL, *b;
1304ebfedea0SLionel Sambuc     getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
1305ebfedea0SLionel Sambuc     print_ifaddrs(a);
1306ebfedea0SLionel Sambuc     printf("---\n");
1307ebfedea0SLionel Sambuc     getifaddrs(&b);
1308ebfedea0SLionel Sambuc     print_ifaddrs(b);
1309ebfedea0SLionel Sambuc     return 0;
1310ebfedea0SLionel Sambuc }
1311ebfedea0SLionel Sambuc #endif
1312