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 #include <sys/types.h>
19 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
25 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
26 #include <sys/sysctl.h>
27 #include <net/route.h>
28 #include <net/if_dl.h>
32 * By including this, we get any system dependencies. In particular,
33 * the pthreads for solaris requires the socket call to be mapped.
35 #include "rx_internal.h"
37 #include "rx_globals.h"
38 #endif /* AFS_NT40_ENV */
41 #include "rx/rx_kcommon.h"
43 #include "rx/rx_internal.h"
51 /* only used for generating random noise */
53 afs_uint32 rxi_tempAddr = 0; /* default attempt */
55 /* set the advisory noise */
57 rxi_setaddr(afs_uint32 x)
62 /* get approx to net addr */
73 /* to satisfy those who call setaddr */
75 rxi_setaddr(afs_uint32 x)
82 #if !defined(AFS_NT40_ENV)
83 /* For NT, rxi_getaddr has moved to rx_user.c. rxi_GetIfInfo is called by
84 * rx_Init which sets up the list of addresses for us.
89 /* Return our internet address as a long in network byte order. Returns zero
90 * if it can't find one.
95 afs_uint32 buffer[1024];
98 count = rx_getAllAddr(buffer, 1024);
100 return buffer[0]; /* returns the first address */
107 #if !defined(KERNEL) || defined(UKERNEL)
110 #define MAX(A,B) (((A)<(B)) ? (B) : (A))
118 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
120 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
121 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
124 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
129 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
130 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
131 if ((rtinfo->rti_addrs & (1 << i)) == 0)
133 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
140 /* this function returns the total number of interface addresses
141 ** the buffer has to be passed in by the caller
143 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
145 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
149 struct if_msghdr *ifm, *nextifm;
150 struct ifa_msghdr *ifam;
151 struct sockaddr_dl *sdl;
152 struct rt_addrinfo info;
153 char *buf, *lim, *next;
154 int count = 0, addrcount = 0;
159 mib[3] = AF_INET; /* address family */
160 mib[4] = NET_RT_IFLIST;
162 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
164 if ((buf = malloc(needed)) == NULL)
166 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
173 ifm = (struct if_msghdr *)next;
174 if (ifm->ifm_type != RTM_IFINFO) {
175 dpf(("out of sync parsing NET_RT_IFLIST\n"));
179 sdl = (struct sockaddr_dl *)(ifm + 1);
180 next += ifm->ifm_msglen;
184 nextifm = (struct if_msghdr *)next;
185 if (nextifm->ifm_type != RTM_NEWADDR)
188 ifam = (struct ifa_msghdr *)nextifm;
190 next += nextifm->ifm_msglen;
192 if ((ifm->ifm_flags & IFF_UP) == 0)
193 continue; /* not up */
194 while (addrcount > 0) {
195 struct sockaddr_in *a;
197 info.rti_addrs = ifam->ifam_addrs;
199 /* Expand the compacted addresses */
200 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
202 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
206 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
208 if (count >= maxSize) /* no more space */
209 dpf(("Too many interfaces..ignoring 0x%x\n",
210 a->sin_addr.s_addr));
211 else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) {
213 continue; /* skip loopback address as well. */
214 } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
216 continue; /* skip aliased loopbacks as well. */
218 buffer[count++] = a->sin_addr.s_addr;
220 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
228 rxi_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
229 afs_uint32 mtuBuffer[], int maxSize)
235 struct if_msghdr *ifm, *nextifm;
236 struct ifa_msghdr *ifam;
237 struct sockaddr_dl *sdl;
238 struct rt_addrinfo info;
239 char *buf, *lim, *next;
240 int count = 0, addrcount = 0;
245 mib[3] = AF_INET; /* address family */
246 mib[4] = NET_RT_IFLIST;
248 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
250 if ((buf = malloc(needed)) == NULL)
252 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
256 s = socket(PF_INET, SOCK_DGRAM, 0);
262 ifm = (struct if_msghdr *)next;
263 if (ifm->ifm_type != RTM_IFINFO) {
264 dpf(("out of sync parsing NET_RT_IFLIST\n"));
268 sdl = (struct sockaddr_dl *)(ifm + 1);
269 next += ifm->ifm_msglen;
273 nextifm = (struct if_msghdr *)next;
274 if (nextifm->ifm_type != RTM_NEWADDR)
277 ifam = (struct ifa_msghdr *)nextifm;
279 next += nextifm->ifm_msglen;
281 if ((ifm->ifm_flags & IFF_UP) == 0)
282 continue; /* not up */
283 while (addrcount > 0) {
284 struct sockaddr_in *a;
286 info.rti_addrs = ifam->ifam_addrs;
288 /* Expand the compacted addresses */
289 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
291 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
295 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
297 if (a->sin_addr.s_addr != htonl(0x7f000001) ) {
298 if (count >= maxSize) { /* no more space */
299 dpf(("Too many interfaces..ignoring 0x%x\n",
300 a->sin_addr.s_addr));
304 addrBuffer[count] = a->sin_addr.s_addr;
305 a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
307 maskBuffer[count] = a->sin_addr.s_addr;
309 maskBuffer[count] = htonl(0xffffffff);
310 memset(&ifr, 0, sizeof(ifr));
311 ifr.ifr_addr.sa_family = AF_INET;
312 strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
313 if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
314 mtuBuffer[count] = htonl(1500);
316 mtuBuffer[count] = htonl(ifr.ifr_mtu);
321 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
330 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
332 return rx_getAllAddr_internal(buffer, maxSize, 0);
334 /* this function returns the total number of interface addresses
335 ** the buffer has to be passed in by the caller
339 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
342 int i, len, count = 0;
344 struct ifreq ifs[NIFS], *ifr;
345 struct sockaddr_in *a;
346 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
347 char *cp, *cplim, *cpnext; /* used only for AIX 41 */
350 s = socket(AF_INET, SOCK_DGRAM, 0);
353 ifc.ifc_len = sizeof(ifs);
354 ifc.ifc_buf = (caddr_t) ifs;
355 i = ioctl(s, SIOCGIFCONF, &ifc);
358 len = ifc.ifc_len / sizeof(struct ifreq);
361 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
362 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
363 ifc.ifc_len = sizeof(ifs);
364 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
366 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
367 cp += _SIZEOF_ADDR_IFREQ(*ifr)
372 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
377 for (i = 0; i < len; ++i)
380 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
381 ifr = (struct ifreq *)cp;
385 a = (struct sockaddr_in *)&ifr->ifr_addr;
387 cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
389 if (a->sin_family != AF_INET)
391 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
392 perror("SIOCGIFFLAGS");
393 continue; /* ignore this address */
395 if (a->sin_addr.s_addr != 0) {
397 if (a->sin_addr.s_addr == htonl(0x7f000001))
398 continue; /* skip loopback address as well. */
400 if (ifr->ifr_flags & IFF_LOOPBACK)
401 continue; /* skip aliased loopbacks as well. */
403 if (count >= maxSize) /* no more space */
404 dpf(("Too many interfaces..ignoring 0x%x\n",
405 a->sin_addr.s_addr));
407 buffer[count++] = a->sin_addr.s_addr;
415 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
417 return rx_getAllAddr_internal(buffer, maxSize, 0);
420 /* this function returns the total number of interface addresses
421 * the buffer has to be passed in by the caller. It also returns
422 * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
423 * gets the mask which is then passed into the kernel and is used
424 * by afsi_SetServerIPRank().
427 rxi_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
428 afs_uint32 mtuBuffer[], int maxSize)
431 int i, len, count = 0;
433 struct ifreq ifs[NIFS], *ifr;
434 struct sockaddr_in *a;
435 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
436 char *cp, *cplim; /* used only for AIX 41 */
439 #if !defined(AFS_USERSPACE_IP_ADDR)
440 count = rx_getAllAddr_internal(addrBuffer, 1024, 0);
441 for (i = 0; i < count; i++) {
442 maskBuffer[i] = htonl(0xffffffff);
443 mtuBuffer[i] = htonl(1500);
446 #else /* AFS_USERSPACE_IP_ADDR */
447 s = socket(AF_INET, SOCK_DGRAM, 0);
451 ifc.ifc_len = sizeof(ifs);
452 ifc.ifc_buf = (caddr_t) ifs;
453 i = ioctl(s, SIOCGIFCONF, &ifc);
458 len = ifc.ifc_len / sizeof(struct ifreq);
462 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
463 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
464 ifc.ifc_len = sizeof(ifs);
465 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
467 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
468 ifr = (struct ifreq *)cp;
470 for (i = 0; i < len; ++i) {
473 a = (struct sockaddr_in *)&ifr->ifr_addr;
474 if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
476 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
477 perror("SIOCGIFFLAGS");
478 continue; /* ignore this address */
481 if (a->sin_addr.s_addr == htonl(0x7f000001) )
482 continue; /* skip loopback address as well. */
484 if (count >= maxSize) { /* no more space */
485 dpf(("Too many interfaces..ignoring 0x%x\n",
486 a->sin_addr.s_addr));
490 addrBuffer[count] = a->sin_addr.s_addr;
492 if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
493 perror("SIOCGIFNETMASK");
494 maskBuffer[count] = htonl(0xffffffff);
496 maskBuffer[count] = (((struct sockaddr_in *)
497 (&ifr->ifr_addr))->sin_addr).s_addr;
500 mtuBuffer[count] = htonl(1500);
502 if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
503 perror("SIOCGIFMTU");
505 mtuBuffer[count] = htonl(ifr->ifr_metric);
507 #endif /* SIOCGIFMTU */
509 if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
510 perror("SIOCRIPMTU");
512 mtuBuffer[count] = htonl(ifr->ifr_metric);
514 #endif /* SIOCRIPMTU */
521 #endif /* AFS_USERSPACE_IP_ADDR */
525 #endif /* ! AFS_NT40_ENV */
526 #endif /* !KERNEL || UKERNEL */