]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/ifname.c
The .Fn function
[FreeBSD/FreeBSD.git] / lib / libc / net / ifname.c
1 /*      $KAME: ifname.c,v 1.4 2001/08/20 02:32:40 itojun Exp $  */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * TODO:
37  * - prototype defs into arpa/inet.h, not net/if.h (bsd-api-new-02)
38  */
39
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/sysctl.h>
44 #include <net/if.h>
45 #include <net/route.h>
46 #include <net/if_dl.h>
47
48 #include <errno.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #define ROUNDUP(a) \
53         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
54 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
55
56 static unsigned int
57 if_onametoindex(ifname)
58         const char *ifname;
59 {
60         struct if_nameindex *iff = if_nameindex(), *ifx;
61         int ret;
62
63         if (iff == NULL) return 0;
64         ifx = iff;
65         while (ifx->if_name != NULL) {
66                 if (strcmp(ifx->if_name, ifname) == 0) {
67                         ret = ifx->if_index;
68                         if_freenameindex(iff);
69                         return ret;
70                 }
71                 ifx++;
72         }
73         if_freenameindex(iff);
74         errno = ENXIO;
75         return 0;
76 }
77  
78 unsigned int
79 if_nametoindex(ifname)
80         const char *ifname;
81 {
82         int s;
83         struct ifreq ifr;
84
85         s = socket(AF_INET, SOCK_DGRAM, 0);
86         if (s == -1)
87                 return (0);
88         strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
89         if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
90                 close (s);
91                 return (if_onametoindex(ifname));
92         }
93         close(s);
94         return (ifr.ifr_index);
95 }
96
97 char *
98 if_indextoname(ifindex, ifname)
99         unsigned int ifindex;
100         char *ifname; /* at least IF_NAMESIZE */
101 {
102         struct if_nameindex *iff = if_nameindex(), *ifx;
103         char *cp, *dp;
104
105         if (iff == NULL) return NULL;
106         ifx = iff;
107         while (ifx->if_index != 0) {
108                 if (ifx->if_index == ifindex) {
109                         cp = ifname;
110                         dp = ifx->if_name;
111                         while ((*cp++ = *dp++)) ;
112                         if_freenameindex(iff);
113                         return (ifname);
114                 }
115                 ifx++;
116         }
117         if_freenameindex(iff);
118         errno = ENXIO;
119         return NULL;
120 }
121
122 struct if_nameindex *
123 if_nameindex()
124 {
125         size_t needed;
126         int mib[6], i, ifn = 0, off = 0, hlen;
127         char *buf = NULL, *lim, *next, *cp, *ifbuf = NULL;
128         struct rt_msghdr *rtm;
129         struct if_msghdr *ifm;
130         struct sockaddr *sa;
131         struct sockaddr_dl *sdl;
132         struct if_nameindex *ret = NULL;
133         static int ifxs = 64;   /* initial upper limit */
134         struct _ifx {
135                 int if_index;
136                 int if_off;
137         } *ifx = NULL;
138
139         mib[0] = CTL_NET;
140         mib[1] = PF_ROUTE;
141         mib[2] = 0;             /* protocol */
142         mib[3] = 0;             /* wildcard address family */
143         mib[4] = NET_RT_IFLIST;
144         mib[5] = 0;             /* no flags */
145         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
146                 return NULL;
147         if ((buf = malloc(needed)) == NULL) {
148                 errno = ENOMEM;
149                 goto end;
150         }
151         /* XXX: we may have allocated too much than necessary */
152         if ((ifbuf = malloc(needed)) == NULL) {
153                 errno = ENOMEM;
154                 goto end;
155         }
156         if ((ifx = (struct _ifx *)malloc(sizeof(*ifx) * ifxs)) == NULL) {
157                 errno = ENOMEM;
158                 goto end;
159         }
160         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
161                 /* sysctl has set errno */
162                 goto end;
163         }
164         lim = buf + needed;
165         for (next = buf; next < lim; next += rtm->rtm_msglen) {
166                 rtm = (struct rt_msghdr *)next;
167                 if (rtm->rtm_version != RTM_VERSION) {
168                         errno = EPROTONOSUPPORT;
169                         goto end;
170                 }
171                 switch (rtm->rtm_type) {
172                 case RTM_IFINFO:
173                         ifm = (struct if_msghdr *)rtm;
174                         ifx[ifn].if_index = ifm->ifm_index;
175                         ifx[ifn].if_off = off;
176                         cp = (char *)(ifm + 1);
177                         for (i = 1; i; i <<= 1) {
178                                 if (i & ifm->ifm_addrs) {
179                                         sa = (struct sockaddr *)cp;
180                                         if (i == RTA_IFP &&
181                                             sa->sa_family == AF_LINK) {
182                                                 sdl = (struct sockaddr_dl *)sa;
183                                                 memcpy(ifbuf + off,
184                                                        sdl->sdl_data,
185                                                        sdl->sdl_nlen);
186                                                 off += sdl->sdl_nlen;
187                                                 *(ifbuf + off) = '\0';
188                                                 off++;
189                                         }
190                                         ADVANCE(cp, sa);
191                                 }
192                         }
193                         if (++ifn == ifxs) {
194                                 /* we need more memory */
195                                 struct _ifx *newifx;
196
197                                 ifxs *= 2;
198                                 if ((newifx = (struct _ifx *)malloc(sizeof(*newifx) * ifxs)) == NULL) {
199                                         errno = ENOMEM;
200                                         goto end;
201                                 }
202
203                                 /* copy and free old data */
204                                 memcpy(newifx, ifx, (sizeof(*ifx) * ifxs) / 2);
205                                 free(ifx);
206                                 ifx = newifx;
207                         }
208                 }
209         }
210         hlen = sizeof(struct if_nameindex) * (ifn + 1);
211         if ((cp = (char *)malloc(hlen + off)) == NULL) {
212                 errno = ENOMEM;
213                 goto end;
214         }
215         bcopy(ifbuf, cp + hlen, off);
216         ret = (struct if_nameindex *)cp;
217         for (i = 0; i < ifn; i++) {
218                 ret[i].if_index = ifx[i].if_index;
219                 ret[i].if_name = cp + hlen + ifx[i].if_off;
220         }
221         ret[ifn].if_index = 0;
222         ret[ifn].if_name = NULL;
223
224   end:
225         if (buf) free(buf);
226         if (ifbuf) free(ifbuf);
227         if (ifx) free(ifx);
228
229         return ret;
230 }
231
232 void if_freenameindex(ptr)
233         struct if_nameindex *ptr;
234 {
235         free(ptr);
236 }