1 /* $FreeBSD: src/lib/libc/net/getifaddrs.c,v 1.1.2.4 2002/08/01 19:31:06 ume Exp $ */ 2 /* $DragonFly: src/lib/libc/net/getifaddrs.c,v 1.3 2003/07/13 05:45:05 dillon Exp $ */ 3 /* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */ 4 5 /* 6 * Copyright (c) 1995, 1999 7 * Berkeley Software Design, Inc. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp 28 */ 29 /* 30 * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform 31 * try-and-error for region size. 32 */ 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/ioctl.h> 36 #include <sys/socket.h> 37 #include <net/if.h> 38 #ifdef NET_RT_IFLIST 39 #include <net/route.h> 40 #include <sys/sysctl.h> 41 #include <net/if_dl.h> 42 #endif 43 44 #include <errno.h> 45 #include <ifaddrs.h> 46 #include <stdlib.h> 47 #include <string.h> 48 49 #if !defined(AF_LINK) 50 #define SA_LEN(sa) sizeof(struct sockaddr) 51 #endif 52 53 #if !defined(SA_LEN) 54 #define SA_LEN(sa) (sa)->sa_len 55 #endif 56 57 #define SALIGN (sizeof(long) - 1) 58 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) 59 60 #ifndef ALIGNBYTES 61 /* 62 * On systems with a routing socket, ALIGNBYTES should match the value 63 * that the kernel uses when building the messages. 64 */ 65 #define ALIGNBYTES XXX 66 #endif 67 #ifndef ALIGN 68 #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES) 69 #endif 70 71 #if _BSDI_VERSION >= 199701 72 #define HAVE_IFM_DATA 73 #endif 74 75 #if _BSDI_VERSION >= 199802 76 /* ifam_data is very specific to recent versions of bsdi */ 77 #define HAVE_IFAM_DATA 78 #endif 79 80 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) 81 #define HAVE_IFM_DATA 82 #endif 83 84 #define MAX_SYSCTL_TRY 5 85 86 int 87 getifaddrs(struct ifaddrs **pif) 88 { 89 int icnt = 1; 90 int dcnt = 0; 91 int ncnt = 0; 92 #ifdef NET_RT_IFLIST 93 int ntry = 0; 94 int mib[6]; 95 size_t needed; 96 char *buf; 97 char *next; 98 struct ifaddrs *cif = 0; 99 char *p, *p0; 100 struct rt_msghdr *rtm; 101 struct if_msghdr *ifm; 102 struct ifa_msghdr *ifam; 103 struct sockaddr_dl *dl; 104 struct sockaddr *sa; 105 struct ifaddrs *ifa, *ift; 106 u_short idx = 0; 107 #else /* NET_RT_IFLIST */ 108 char buf[1024]; 109 int m, sock; 110 struct ifconf ifc; 111 struct ifreq *ifr; 112 struct ifreq *lifr; 113 #endif /* NET_RT_IFLIST */ 114 int i; 115 size_t len, alen; 116 char *data; 117 char *names; 118 119 #ifdef NET_RT_IFLIST 120 mib[0] = CTL_NET; 121 mib[1] = PF_ROUTE; 122 mib[2] = 0; /* protocol */ 123 mib[3] = 0; /* wildcard address family */ 124 mib[4] = NET_RT_IFLIST; 125 mib[5] = 0; /* no flags */ 126 do { 127 /* 128 * We'll try to get addresses several times in case that 129 * the number of addresses is unexpectedly increased during 130 * the two sysctl calls. This should rarely happen, but we'll 131 * try to do our best for applications that assume success of 132 * this library (which should usually be the case). 133 * Portability note: since FreeBSD does not add margin of 134 * memory at the first sysctl, the possibility of failure on 135 * the second sysctl call is a bit higher. 136 */ 137 138 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 139 return (-1); 140 if ((buf = malloc(needed)) == NULL) 141 return (-1); 142 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 143 if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { 144 free(buf); 145 return (-1); 146 } 147 free(buf); 148 buf = NULL; 149 } 150 } while (buf == NULL); 151 152 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 153 rtm = (struct rt_msghdr *)(void *)next; 154 if (rtm->rtm_version != RTM_VERSION) 155 continue; 156 switch (rtm->rtm_type) { 157 case RTM_IFINFO: 158 ifm = (struct if_msghdr *)(void *)rtm; 159 if (ifm->ifm_addrs & RTA_IFP) { 160 idx = ifm->ifm_index; 161 ++icnt; 162 dl = (struct sockaddr_dl *)(void *)(ifm + 1); 163 dcnt += SA_RLEN((struct sockaddr *)(void*)dl) + 164 ALIGNBYTES; 165 #ifdef HAVE_IFM_DATA 166 dcnt += sizeof(ifm->ifm_data); 167 #endif /* HAVE_IFM_DATA */ 168 ncnt += dl->sdl_nlen + 1; 169 } else 170 idx = 0; 171 break; 172 173 case RTM_NEWADDR: 174 ifam = (struct ifa_msghdr *)(void *)rtm; 175 if (idx && ifam->ifam_index != idx) 176 abort(); /* this cannot happen */ 177 178 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) 179 if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) 180 break; 181 p = (char *)(void *)(ifam + 1); 182 ++icnt; 183 #ifdef HAVE_IFAM_DATA 184 dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES; 185 #endif /* HAVE_IFAM_DATA */ 186 /* Scan to look for length of address */ 187 alen = 0; 188 for (p0 = p, i = 0; i < RTAX_MAX; i++) { 189 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 190 == 0) 191 continue; 192 sa = (struct sockaddr *)(void *)p; 193 len = SA_RLEN(sa); 194 if (i == RTAX_IFA) { 195 alen = len; 196 break; 197 } 198 p += len; 199 } 200 for (p = p0, i = 0; i < RTAX_MAX; i++) { 201 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 202 == 0) 203 continue; 204 sa = (struct sockaddr *)(void *)p; 205 len = SA_RLEN(sa); 206 if (i == RTAX_NETMASK && SA_LEN(sa) == 0) 207 dcnt += alen; 208 else 209 dcnt += len; 210 p += len; 211 } 212 break; 213 } 214 } 215 #else /* NET_RT_IFLIST */ 216 ifc.ifc_buf = buf; 217 ifc.ifc_len = sizeof(buf); 218 219 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 220 return (-1); 221 i = ioctl(sock, SIOCGIFCONF, (char *)&ifc); 222 close(sock); 223 if (i < 0) 224 return (-1); 225 226 ifr = ifc.ifc_req; 227 lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; 228 229 while (ifr < lifr) { 230 struct sockaddr *sa; 231 232 sa = &ifr->ifr_addr; 233 ++icnt; 234 dcnt += SA_RLEN(sa); 235 ncnt += sizeof(ifr->ifr_name) + 1; 236 237 if (SA_LEN(sa) < sizeof(*sa)) 238 ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); 239 else 240 ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); 241 } 242 #endif /* NET_RT_IFLIST */ 243 244 if (icnt + dcnt + ncnt == 1) { 245 *pif = NULL; 246 free(buf); 247 return (0); 248 } 249 data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); 250 if (data == NULL) { 251 free(buf); 252 return(-1); 253 } 254 255 ifa = (struct ifaddrs *)(void *)data; 256 data += sizeof(struct ifaddrs) * icnt; 257 names = data + dcnt; 258 259 memset(ifa, 0, sizeof(struct ifaddrs) * icnt); 260 ift = ifa; 261 262 #ifdef NET_RT_IFLIST 263 idx = 0; 264 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 265 rtm = (struct rt_msghdr *)(void *)next; 266 if (rtm->rtm_version != RTM_VERSION) 267 continue; 268 switch (rtm->rtm_type) { 269 case RTM_IFINFO: 270 ifm = (struct if_msghdr *)(void *)rtm; 271 if (ifm->ifm_addrs & RTA_IFP) { 272 idx = ifm->ifm_index; 273 dl = (struct sockaddr_dl *)(void *)(ifm + 1); 274 275 cif = ift; 276 ift->ifa_name = names; 277 ift->ifa_flags = (int)ifm->ifm_flags; 278 memcpy(names, dl->sdl_data, 279 (size_t)dl->sdl_nlen); 280 names[dl->sdl_nlen] = 0; 281 names += dl->sdl_nlen + 1; 282 283 ift->ifa_addr = (struct sockaddr *)(void *)data; 284 memcpy(data, dl, 285 (size_t)SA_LEN((struct sockaddr *) 286 (void *)dl)); 287 data += SA_RLEN((struct sockaddr *)(void *)dl); 288 289 #ifdef HAVE_IFM_DATA 290 /* ifm_data needs to be aligned */ 291 ift->ifa_data = data = (void *)ALIGN(data); 292 memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); 293 data += sizeof(ifm->ifm_data); 294 #else /* HAVE_IFM_DATA */ 295 ift->ifa_data = NULL; 296 #endif /* HAVE_IFM_DATA */ 297 298 ift = (ift->ifa_next = ift + 1); 299 } else 300 idx = 0; 301 break; 302 303 case RTM_NEWADDR: 304 ifam = (struct ifa_msghdr *)(void *)rtm; 305 if (idx && ifam->ifam_index != idx) 306 abort(); /* this cannot happen */ 307 308 if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) 309 break; 310 ift->ifa_name = cif->ifa_name; 311 ift->ifa_flags = cif->ifa_flags; 312 ift->ifa_data = NULL; 313 p = (char *)(void *)(ifam + 1); 314 /* Scan to look for length of address */ 315 alen = 0; 316 for (p0 = p, i = 0; i < RTAX_MAX; i++) { 317 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 318 == 0) 319 continue; 320 sa = (struct sockaddr *)(void *)p; 321 len = SA_RLEN(sa); 322 if (i == RTAX_IFA) { 323 alen = len; 324 break; 325 } 326 p += len; 327 } 328 for (p = p0, i = 0; i < RTAX_MAX; i++) { 329 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 330 == 0) 331 continue; 332 sa = (struct sockaddr *)(void *)p; 333 len = SA_RLEN(sa); 334 switch (i) { 335 case RTAX_IFA: 336 ift->ifa_addr = 337 (struct sockaddr *)(void *)data; 338 memcpy(data, p, len); 339 data += len; 340 break; 341 342 case RTAX_NETMASK: 343 ift->ifa_netmask = 344 (struct sockaddr *)(void *)data; 345 if (SA_LEN(sa) == 0) { 346 memset(data, 0, alen); 347 data += alen; 348 break; 349 } 350 memcpy(data, p, len); 351 data += len; 352 break; 353 354 case RTAX_BRD: 355 ift->ifa_broadaddr = 356 (struct sockaddr *)(void *)data; 357 memcpy(data, p, len); 358 data += len; 359 break; 360 } 361 p += len; 362 } 363 364 #ifdef HAVE_IFAM_DATA 365 /* ifam_data needs to be aligned */ 366 ift->ifa_data = data = (void *)ALIGN(data); 367 memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data)); 368 data += sizeof(ifam->ifam_data); 369 #endif /* HAVE_IFAM_DATA */ 370 371 ift = (ift->ifa_next = ift + 1); 372 break; 373 } 374 } 375 376 free(buf); 377 #else /* NET_RT_IFLIST */ 378 ifr = ifc.ifc_req; 379 lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; 380 381 while (ifr < lifr) { 382 struct sockaddr *sa; 383 384 ift->ifa_name = names; 385 names[sizeof(ifr->ifr_name)] = 0; 386 strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); 387 while (*names++) 388 ; 389 390 ift->ifa_addr = (struct sockaddr *)data; 391 sa = &ifr->ifr_addr; 392 memcpy(data, sa, SA_LEN(sa)); 393 data += SA_RLEN(sa); 394 395 ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); 396 ift = (ift->ifa_next = ift + 1); 397 } 398 #endif /* NET_RT_IFLIST */ 399 if (--ift >= ifa) { 400 ift->ifa_next = NULL; 401 *pif = ifa; 402 } else { 403 *pif = NULL; 404 free(ifa); 405 } 406 return (0); 407 } 408 409 void 410 freeifaddrs(struct ifaddrs *ifp) 411 { 412 413 free(ifp); 414 } 415