]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/common/v2_0/src/ifaddrs.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / common / v2_0 / src / ifaddrs.c
1 //==========================================================================
2 //
3 //      src/ifaddrs.c
4 //
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
7 //
8 // -------------------------------------------
9 //
10 // Portions of this software may have been derived from OpenBSD, 
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
13 //
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16 //
17 // -------------------------------------------
18 //
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
21
22 //
23 // Adapted from KAME getifaddrs.c, if_nametoindex.c, if_indextoname.c
24 //
25
26 /*      $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $      */
27 /*      $KAME: if_nametoindex.c,v 1.6 2000/11/24 08:18:54 itojun Exp $  */
28 /*      $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $  */
29
30 /*
31  * Copyright (c) 1995, 1999
32  *      Berkeley Software Design, Inc.  All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  *
40  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  *      BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
53  */
54
55 #include <cyg/infra/diag.h>
56
57 #include <unistd.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #undef _KERNEL
62 #undef __INSIDE_NET
63 #include <sys/param.h>
64 #include <sys/types.h>
65 #include <sys/ioctl.h>
66 #include <sys/socket.h>
67 #include <net/if.h>
68 #include <net/if_dl.h>
69 #ifndef CYGPKG_NET_OPENBSD_STACK
70 #include <net/if_var.h>
71 #endif
72 #include <errno.h>
73 #include <netinet/in.h>
74 #include <net/netdb.h>
75 #include <ifaddrs.h>
76 #include <netinet/in_var.h>
77
78
79 #if !defined(AF_LINK)
80 #define SA_LEN(sa)      sizeof(struct sockaddr)
81 #endif
82
83 #if !defined(SA_LEN)
84 #define SA_LEN(sa)      (sa)->sa_len
85 #endif
86
87 #define SALIGN  (sizeof(long) - 1)
88 #define SA_RLEN(sa)     ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
89
90 #ifndef ALIGNBYTES
91 /*
92  * On systems with a routing socket, ALIGNBYTES should match the value
93  * that the kernel uses when building the messages.
94  */
95 #define ALIGNBYTES      XXX
96 #endif
97 #ifndef ALIGN
98 #define ALIGN(p)        (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
99 #endif
100
101 int
102 getifaddrs(struct ifaddrs **pif)
103 {
104     int icnt = 1;  // Interface count
105     int dcnt = 0;  // Data [length] count
106     int ncnt = 0;  // Length of interface names
107     char *buf;
108 #define IF_WORK_SPACE_SZ        1024
109     int i, sock;
110 #ifdef CYGPKG_NET_INET6
111     int sock6;
112     struct in6_ifreq ifrq6;
113 #endif
114     struct ifconf ifc;
115     struct ifreq *ifr, *lifr;
116     struct ifreq ifrq;
117     char *data, *names;
118     struct ifaddrs *ifa, *ift;
119
120     buf = malloc(IF_WORK_SPACE_SZ);
121     if (buf == NULL)
122         return (-1);
123     ifc.ifc_buf = buf;
124     ifc.ifc_len = IF_WORK_SPACE_SZ;
125
126     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
127     {
128         free(buf);
129         return (-1);
130     }
131     i =  ioctl(sock, SIOCGIFCONF, (char *)&ifc);
132
133     if (i < 0) {
134         close(sock); 
135         free(buf);
136         return (-1);
137     }
138
139     ifr = ifc.ifc_req;
140     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
141
142     while (ifr < lifr) {
143         struct sockaddr *sa;
144
145         sa = &ifr->ifr_addr;
146         ++icnt;
147         dcnt += SA_RLEN(sa) * 3;  /* addr, mask, brdcst */
148         ncnt += sizeof(ifr->ifr_name) + 1;
149                 
150         if (SA_LEN(sa) < sizeof(*sa))
151             ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
152         else
153             ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
154     }
155
156     if (icnt + dcnt + ncnt == 1) {
157         // Nothing found
158         *pif = NULL;
159         free(buf);
160         close(sock);
161         return (0);
162     }
163     data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
164     if (data == NULL) {
165         free(buf);
166         close(sock);
167         return(-1);
168     }
169
170     ifa = (struct ifaddrs *)(void *)data;
171     data += sizeof(struct ifaddrs) * icnt;
172     names = data + dcnt;
173
174     memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
175     ift = ifa;
176
177     ifr = ifc.ifc_req;
178
179 #ifdef CYGPKG_NET_INET6
180     if ((sock6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
181       free(buf);
182       free(data);
183       close(sock);
184       return (-1);
185     }
186 #endif
187
188     while (ifr < lifr) {
189        struct sockaddr * sa;
190
191         ift->ifa_name = names;
192         names[sizeof(ifr->ifr_name)] = 0;
193         strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
194         while (*names++) ;
195
196         ift->ifa_addr = (struct sockaddr *)data;
197         sa = &ifr->ifr_addr;
198         memcpy(data, sa, SA_LEN(sa));
199         data += SA_RLEN(sa);
200
201         if ((sa->sa_family == AF_INET) || (sa->sa_family == AF_INET6)) {
202           struct sockaddr *sa_netmask = NULL;
203           struct sockaddr *sa_broadcast = NULL;
204           struct sockaddr *sa_dst = NULL;
205           
206           memset(&ifrq,0,sizeof(ifrq));
207           strcpy(ifrq.ifr_name,ifr->ifr_name);
208           ioctl( sock, SIOCGIFFLAGS, &ifrq );
209
210           ift->ifa_flags = ifrq.ifr_flags;
211
212           memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
213           if (sa->sa_family == AF_INET) {
214             ioctl(sock, SIOCGIFNETMASK, &ifrq); 
215             sa_netmask = &ifrq.ifr_addr;
216           }
217 #ifdef CYGPKG_NET_INET6
218           if (sa->sa_family == AF_INET6) {
219             memset(&ifrq6,0,sizeof(ifrq));
220             strcpy(ifrq6.ifr_name,ifr->ifr_name);
221             memcpy(&ifrq6.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
222           
223             ioctl(sock6, SIOCGIFNETMASK_IN6, &ifrq6);
224             sa_netmask = (struct sockaddr *)&ifrq6.ifr_addr;
225           }
226 #endif
227           ift->ifa_netmask = (struct sockaddr *)data;
228           memcpy(data, sa_netmask, SA_LEN(sa_netmask));
229           data += SA_RLEN(sa_netmask);
230
231           memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
232           if ((sa->sa_family == AF_INET) && (ift->ifa_flags & IFF_BROADCAST)) {
233             if (ioctl(sock, SIOCGIFBRDADDR, &ifrq) == 0) {
234               sa_broadcast = &ifrq.ifr_addr;
235               ift->ifa_broadaddr = (struct sockaddr *)data;
236               memcpy(data, sa_broadcast, SA_LEN(sa_broadcast));
237               data += SA_RLEN(sa_broadcast);
238             }
239           }
240
241           memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
242           if ((sa->sa_family == AF_INET) && 
243               (ift->ifa_flags & IFF_POINTOPOINT)) {
244             if (ioctl(sock, SIOCGIFDSTADDR, &ifrq) == 0) {
245               sa_dst = &ifrq.ifr_addr;
246               ift->ifa_dstaddr = (struct sockaddr *)data;
247               memcpy(data, sa_dst, SA_LEN(sa_dst));
248               data += SA_RLEN(sa_dst);
249             }
250           }
251         }
252         
253         if (SA_LEN(sa) < sizeof(*sa))
254             ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
255         else
256             ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
257         ift = (ift->ifa_next = ift + 1);
258     }
259     free(buf);
260
261     if (--ift >= ifa) {
262         ift->ifa_next = NULL;
263         *pif = ifa;
264     } else {
265         *pif = NULL;
266         free(ifa);
267     }
268 #ifdef CYGPKG_NET_INET6
269     close(sock6);
270 #endif
271     close(sock);
272     return (0);
273 }
274
275 void
276 freeifaddrs(struct ifaddrs *ifp)
277 {
278     free(ifp);
279 }
280
281 void
282 _show_all_interfaces(void)
283 {
284     struct ifaddrs *iflist, *ifp;
285     char addr[64];
286     int indx;
287
288     if (getifaddrs(&iflist) < 0) {
289         diag_printf("Can't get interface information!!\n");
290         return;
291     }
292     ifp = iflist;
293     while (ifp != (struct ifaddrs *)NULL) {
294         if (ifp->ifa_addr->sa_family != AF_LINK) {
295             getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr, 
296                          sizeof(addr), 0, 0, NI_NUMERICHOST);
297             diag_printf("%p - %s - %s\n", ifp, ifp->ifa_name, addr);
298         }
299         ifp = ifp->ifa_next;
300     }
301     indx = if_nametoindex(iflist->ifa_name);
302     diag_printf("indx(%s) = %d\n", iflist->ifa_name, indx);
303     if (indx > 0) {
304         if (if_indextoname(indx, addr)) {
305             diag_printf("index(%s) = %d/%s\n", iflist->ifa_name, indx, addr);
306         } else {
307             diag_printf("index(%s) = %d: %s\n", iflist->ifa_name, indx, strerror(errno));
308         }
309     } else {
310         diag_printf("index(%s): %s\n", iflist->ifa_name, strerror(errno));
311     }
312     freeifaddrs(iflist);
313 }
314
315 /*
316  * From RFC 2553:
317  *
318  * 4.1 Name-to-Index
319  *
320  *
321  *    The first function maps an interface name into its corresponding
322  *    index.
323  *
324  *       #include <net/if.h>
325  *
326  *       unsigned int  if_nametoindex(const char *ifname);
327  *
328  *    If the specified interface name does not exist, the return value is
329  *    0, and errno is set to ENXIO.  If there was a system error (such as
330  *    running out of memory), the return value is 0 and errno is set to the
331  *    proper value (e.g., ENOMEM).
332  */
333
334 unsigned int
335 if_nametoindex(const char *ifname)
336 {
337     struct ifaddrs *ifaddrs, *ifa;
338     unsigned int ni;
339
340     if (getifaddrs(&ifaddrs) < 0)
341         return(0);
342
343     ni = 0;
344
345     for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
346         if (ifa->ifa_addr &&
347             ifa->ifa_addr->sa_family == AF_LINK &&
348             strcmp(ifa->ifa_name, ifname) == 0) {
349             ni = ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
350             break;
351         }
352     }
353
354     freeifaddrs(ifaddrs);
355     if (!ni)
356         errno = ENXIO;
357     return(ni);
358 }
359
360 /*
361  * From RFC 2533:
362  *
363  * The second function maps an interface index into its corresponding
364  * name.
365  *
366  *    #include <net/if.h>
367  *
368  *    char  *if_indextoname(unsigned int ifindex, char *ifname);
369  *
370  * The ifname argument must point to a buffer of at least IF_NAMESIZE
371  * bytes into which the interface name corresponding to the specified
372  * index is returned.  (IF_NAMESIZE is also defined in <net/if.h> and
373  * its value includes a terminating null byte at the end of the
374  * interface name.) This pointer is also the return value of the
375  * function.  If there is no interface corresponding to the specified
376  * index, NULL is returned, and errno is set to ENXIO, if there was a
377  * system error (such as running out of memory), if_indextoname returns
378  * NULL and errno would be set to the proper value (e.g., ENOMEM).
379  */
380
381 char *
382 if_indextoname(unsigned int ifindex, char *ifname)
383 {
384     struct ifaddrs *ifaddrs, *ifa;
385     int error = 0;
386
387     if (getifaddrs(&ifaddrs) < 0)
388         return(NULL);   /* getifaddrs properly set errno */
389
390     for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
391         if (ifa->ifa_addr &&
392             ifa->ifa_addr->sa_family == AF_LINK &&
393             ifindex == ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index)
394             break;
395     }
396
397     if (ifa == NULL) {
398         error = ENXIO;
399         ifname = NULL;
400     }
401     else
402         strncpy(ifname, ifa->ifa_name, IFNAMSIZ);
403
404     freeifaddrs(ifaddrs);
405
406     errno = error;
407     return(ifname);
408 }