2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
19 # include <sys/sysctl.h>
20 # ifndef AFS_ARM_DARWIN_ENV
21 # include <net/route.h>
23 # include <net/if_dl.h>
27 * By including this, we get any system dependencies. In particular,
28 * the pthreads for solaris requires the socket call to be mapped.
31 # include "rx_globals.h"
32 # endif /* AFS_NT40_ENV */
35 # include "rx/rx_kcommon.h"
43 #if defined(AFS_USR_DFBSD_ENV)
45 # include <sys/sockio.h>
49 /* only used for generating random noise */
51 afs_uint32 rxi_tempAddr
= 0; /* default attempt */
53 /* set the advisory noise */
55 rxi_setaddr(afs_uint32 x
)
60 /* get approx to net addr */
71 /* to satisfy those who call setaddr */
73 rxi_setaddr(afs_uint32 x
)
80 #if !defined(AFS_NT40_ENV)
81 /* For NT, rxi_getaddr has moved to rx_user.c. rxi_GetIfInfo is called by
82 * rx_Init which sets up the list of addresses for us.
87 /* Return our internet address as a long in network byte order. Returns zero
88 * if it can't find one.
93 afs_uint32 buffer
[1024];
96 count
= rx_getAllAddr(buffer
, 1024);
98 return buffer
[0]; /* returns the first address */
105 #if !defined(KERNEL) || defined(UKERNEL)
108 #define MAX(A,B) (((A)<(B)) ? (B) : (A))
116 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
118 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
119 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
122 rt_xaddrs(caddr_t cp
, caddr_t cplim
, struct rt_addrinfo
*rtinfo
)
127 memset(rtinfo
->rti_info
, 0, sizeof(rtinfo
->rti_info
));
128 for (i
= 0; (i
< RTAX_MAX
) && (cp
< cplim
); i
++) {
129 if ((rtinfo
->rti_addrs
& (1 << i
)) == 0)
131 rtinfo
->rti_info
[i
] = sa
= (struct sockaddr
*)cp
;
138 rxi_IsLoopbackIface(struct sockaddr_in
*a
, unsigned long flags
)
140 afs_uint32 addr
= ntohl(a
->sin_addr
.s_addr
);
141 if (rx_IsLoopbackAddr(addr
)) {
144 if ((flags
& IFF_LOOPBACK
) && ((addr
& 0xff000000) == 0x7f000000)) {
150 /* this function returns the total number of interface addresses
151 ** the buffer has to be passed in by the caller
153 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
154 #if defined(AFS_OBSD42_ENV)
156 ifm_fixversion(char *buffer
, size_t *size
) {
157 struct if_msghdr
*ifm
;
161 if ((t
= malloc(*size
)) != NULL
) {
162 memcpy(t
, buffer
, *size
);
164 for (s
= t
; s
< t
+ *size
; s
+= ifm
->ifm_msglen
) {
165 ifm
= (struct if_msghdr
*)s
;
167 if (ifm
->ifm_version
== RTM_VERSION
) {
168 memcpy(b
, ifm
, ifm
->ifm_msglen
);
169 b
+= ifm
->ifm_msglen
;
181 rx_getAllAddr_internal(afs_uint32 buffer
[], int maxSize
, int loopbacks
)
185 struct if_msghdr
*ifm
, *nextifm
;
186 struct ifa_msghdr
*ifam
;
187 struct rt_addrinfo info
;
188 char *buf
, *lim
, *next
;
189 int count
= 0, addrcount
= 0;
194 mib
[3] = AF_INET
; /* address family */
195 mib
[4] = NET_RT_IFLIST
;
197 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
199 if ((buf
= malloc(needed
)) == NULL
)
201 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
205 #if defined(AFS_OBSD42_ENV)
206 ifm_fixversion(buf
, &needed
);
211 ifm
= (struct if_msghdr
*)next
;
212 if (ifm
->ifm_type
!= RTM_IFINFO
) {
213 dpf(("out of sync parsing NET_RT_IFLIST\n"));
217 next
+= ifm
->ifm_msglen
;
221 nextifm
= (struct if_msghdr
*)next
;
222 if (nextifm
->ifm_type
!= RTM_NEWADDR
)
225 ifam
= (struct ifa_msghdr
*)nextifm
;
227 next
+= nextifm
->ifm_msglen
;
229 if ((ifm
->ifm_flags
& IFF_UP
) == 0)
230 continue; /* not up */
231 while (addrcount
> 0) {
232 struct sockaddr_in
*a
;
234 info
.rti_addrs
= ifam
->ifam_addrs
;
236 /* Expand the compacted addresses */
237 rt_xaddrs((char *)(ifam
+ 1), ifam
->ifam_msglen
+ (char *)ifam
,
239 if (info
.rti_info
[RTAX_IFA
]->sa_family
!= AF_INET
) {
243 a
= (struct sockaddr_in
*) info
.rti_info
[RTAX_IFA
];
245 if (count
>= maxSize
) /* no more space */
246 dpf(("Too many interfaces..ignoring 0x%x\n",
247 a
->sin_addr
.s_addr
));
248 else if (!loopbacks
&& rxi_IsLoopbackIface(a
, ifm
->ifm_flags
)) {
250 continue; /* skip loopback address as well. */
251 } else if (loopbacks
&& ifm
->ifm_flags
& IFF_LOOPBACK
) {
253 continue; /* skip aliased loopbacks as well. */
255 buffer
[count
++] = a
->sin_addr
.s_addr
;
257 ifam
= (struct ifa_msghdr
*)((char *)ifam
+ ifam
->ifam_msglen
);
265 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer
[], afs_uint32 maskBuffer
[],
266 afs_uint32 mtuBuffer
[], int maxSize
)
272 struct if_msghdr
*ifm
, *nextifm
;
273 struct ifa_msghdr
*ifam
;
274 struct sockaddr_dl
*sdl
;
275 struct rt_addrinfo info
;
276 char *buf
, *lim
, *next
;
277 int count
= 0, addrcount
= 0;
282 mib
[3] = AF_INET
; /* address family */
283 mib
[4] = NET_RT_IFLIST
;
285 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
287 if ((buf
= malloc(needed
)) == NULL
)
289 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
293 #if defined(AFS_OBSD42_ENV)
294 ifm_fixversion(buf
, &needed
);
296 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
302 ifm
= (struct if_msghdr
*)next
;
303 if (ifm
->ifm_type
!= RTM_IFINFO
) {
304 dpf(("out of sync parsing NET_RT_IFLIST\n"));
308 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
309 next
+= ifm
->ifm_msglen
;
313 nextifm
= (struct if_msghdr
*)next
;
314 if (nextifm
->ifm_type
!= RTM_NEWADDR
)
317 ifam
= (struct ifa_msghdr
*)nextifm
;
319 next
+= nextifm
->ifm_msglen
;
321 if ((ifm
->ifm_flags
& IFF_UP
) == 0)
322 continue; /* not up */
323 while (addrcount
> 0) {
324 struct sockaddr_in
*a
;
326 info
.rti_addrs
= ifam
->ifam_addrs
;
328 /* Expand the compacted addresses */
329 rt_xaddrs((char *)(ifam
+ 1), ifam
->ifam_msglen
+ (char *)ifam
,
331 if (info
.rti_info
[RTAX_IFA
]->sa_family
!= AF_INET
) {
335 a
= (struct sockaddr_in
*) info
.rti_info
[RTAX_IFA
];
337 if (!rx_IsLoopbackAddr(ntohl(a
->sin_addr
.s_addr
))) {
338 if (count
>= maxSize
) { /* no more space */
339 dpf(("Too many interfaces..ignoring 0x%x\n",
340 a
->sin_addr
.s_addr
));
344 addrBuffer
[count
] = a
->sin_addr
.s_addr
;
345 a
= (struct sockaddr_in
*) info
.rti_info
[RTAX_NETMASK
];
347 maskBuffer
[count
] = a
->sin_addr
.s_addr
;
349 maskBuffer
[count
] = htonl(0xffffffff);
350 memset(&ifr
, 0, sizeof(ifr
));
351 ifr
.ifr_addr
.sa_family
= AF_INET
;
352 strncpy(ifr
.ifr_name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
353 if (ioctl(s
, SIOCGIFMTU
, (caddr_t
) & ifr
) < 0)
354 mtuBuffer
[count
] = htonl(1500);
356 mtuBuffer
[count
] = htonl(ifr
.ifr_mtu
);
361 ifam
= (struct ifa_msghdr
*)((char *)ifam
+ ifam
->ifam_msglen
);
370 rx_getAllAddr(afs_uint32 buffer
[], int maxSize
)
372 return rx_getAllAddr_internal(buffer
, maxSize
, 0);
374 /* this function returns the total number of interface addresses
375 ** the buffer has to be passed in by the caller
377 #else /* UKERNEL indirectly, on DARWIN or XBSD */
379 rx_getAllAddr_internal(afs_uint32 buffer
[], int maxSize
, int loopbacks
)
382 int i
, len
, count
= 0;
384 struct ifreq ifs
[NIFS
], *ifr
;
385 struct sockaddr_in
*a
;
386 /* can't ever be AFS_DARWIN_ENV or AFS_XBSD_ENV, no? */
387 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
388 char *cp
, *cplim
, *cpnext
; /* used only for AIX 41 */
391 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
394 ifc
.ifc_len
= sizeof(ifs
);
395 ifc
.ifc_buf
= (caddr_t
) ifs
;
396 i
= ioctl(s
, SIOCGIFCONF
, &ifc
);
399 len
= ifc
.ifc_len
/ sizeof(struct ifreq
);
402 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
403 if (ifc
.ifc_len
> sizeof(ifs
)) /* safety check */
404 ifc
.ifc_len
= sizeof(ifs
);
405 for (cp
= (char *)ifc
.ifc_buf
, cplim
= ifc
.ifc_buf
+ ifc
.ifc_len
;
407 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
408 cp
+= _SIZEOF_ADDR_IFREQ(*ifr
)
413 cp
+= sizeof(ifr
->ifr_name
) + MAX(a
->sin_len
, sizeof(*a
))
418 for (i
= 0; i
< len
; ++i
)
421 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
422 ifr
= (struct ifreq
*)cp
;
426 a
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
428 cpnext
= cp
+ sizeof(ifr
->ifr_name
) + MAX(a
->sin_len
, sizeof(*a
));
430 if (a
->sin_family
!= AF_INET
)
432 if (ioctl(s
, SIOCGIFFLAGS
, ifr
) < 0) {
433 perror("SIOCGIFFLAGS");
434 continue; /* ignore this address */
436 if (a
->sin_addr
.s_addr
!= 0) {
438 if (rxi_IsLoopbackIface(a
, ifr
->ifr_flags
))
439 continue; /* skip loopback address as well. */
441 if (ifr
->ifr_flags
& IFF_LOOPBACK
)
442 continue; /* skip aliased loopbacks as well. */
444 if (count
>= maxSize
) /* no more space */
445 dpf(("Too many interfaces..ignoring 0x%x\n",
446 a
->sin_addr
.s_addr
));
448 buffer
[count
++] = a
->sin_addr
.s_addr
;
456 rx_getAllAddr(afs_uint32 buffer
[], int maxSize
)
458 return rx_getAllAddr_internal(buffer
, maxSize
, 0);
461 /* this function returns the total number of interface addresses
462 * the buffer has to be passed in by the caller. It also returns
463 * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
464 * gets the mask which is then passed into the kernel and is used
465 * by afsi_SetServerIPRank().
468 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer
[], afs_uint32 maskBuffer
[],
469 afs_uint32 mtuBuffer
[], int maxSize
)
472 #if defined(AFS_USERSPACE_IP_ADDR)
475 struct ifreq ifs
[NIFS
], *ifr
;
476 struct sockaddr_in
*a
;
479 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
480 char *cp
, *cplim
; /* used only for AIX 41 */
483 #if !defined(AFS_USERSPACE_IP_ADDR)
484 count
= rx_getAllAddr_internal(addrBuffer
, 1024, 0);
485 for (i
= 0; i
< count
; i
++) {
486 maskBuffer
[i
] = htonl(0xffffffff);
487 mtuBuffer
[i
] = htonl(1500);
490 #else /* AFS_USERSPACE_IP_ADDR */
491 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
495 ifc
.ifc_len
= sizeof(ifs
);
496 ifc
.ifc_buf
= (caddr_t
) ifs
;
497 i
= ioctl(s
, SIOCGIFCONF
, &ifc
);
502 len
= ifc
.ifc_len
/ sizeof(struct ifreq
);
506 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
507 if (ifc
.ifc_len
> sizeof(ifs
)) /* safety check */
508 ifc
.ifc_len
= sizeof(ifs
);
509 for (cp
= (char *)ifc
.ifc_buf
, cplim
= ifc
.ifc_buf
+ ifc
.ifc_len
;
511 cp
+= sizeof(ifr
->ifr_name
) + MAX(a
->sin_len
, sizeof(*a
))) {
512 ifr
= (struct ifreq
*)cp
;
514 for (i
= 0; i
< len
; ++i
) {
517 a
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
518 if (a
->sin_addr
.s_addr
!= 0 && a
->sin_family
== AF_INET
) {
520 if (ioctl(s
, SIOCGIFFLAGS
, ifr
) < 0) {
521 perror("SIOCGIFFLAGS");
522 continue; /* ignore this address */
525 if (rx_IsLoopbackAddr(ntohl(a
->sin_addr
.s_addr
)))
526 continue; /* skip loopback address as well. */
528 if (count
>= maxSize
) { /* no more space */
529 dpf(("Too many interfaces..ignoring 0x%x\n",
530 a
->sin_addr
.s_addr
));
534 addrBuffer
[count
] = a
->sin_addr
.s_addr
;
536 if (ioctl(s
, SIOCGIFNETMASK
, (caddr_t
) ifr
) < 0) {
537 perror("SIOCGIFNETMASK");
538 maskBuffer
[count
] = htonl(0xffffffff);
540 maskBuffer
[count
] = (((struct sockaddr_in
*)
541 (&ifr
->ifr_addr
))->sin_addr
).s_addr
;
544 mtuBuffer
[count
] = htonl(1500);
546 if (ioctl(s
, SIOCGIFMTU
, (caddr_t
) ifr
) < 0) {
547 perror("SIOCGIFMTU");
549 mtuBuffer
[count
] = htonl(ifr
->ifr_metric
);
551 #endif /* SIOCGIFMTU */
553 if (ioctl(s
, SIOCRIPMTU
, (caddr_t
) ifr
) < 0) {
554 perror("SIOCRIPMTU");
556 mtuBuffer
[count
] = htonl(ifr
->ifr_metric
);
558 #endif /* SIOCRIPMTU */
565 #endif /* AFS_USERSPACE_IP_ADDR */
569 #endif /* ! AFS_NT40_ENV */
570 #endif /* !KERNEL || UKERNEL */