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>
16 #include <sys/types.h>
17 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <sys/ioctl.h>
23 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
24 #include <sys/sysctl.h>
25 #include <net/route.h>
26 #include <net/if_dl.h>
30 * By including this, we get any system dependencies. In particular,
31 * the pthreads for solaris requires the socket call to be mapped.
34 #include "rx_globals.h"
35 #endif /* AFS_NT40_ENV */
38 #include "rx/rx_kcommon.h"
46 #if defined(AFS_USR_DFBSD_ENV)
48 #include <sys/sockio.h>
52 /* only used for generating random noise */
54 afs_uint32 rxi_tempAddr = 0; /* default attempt */
56 /* set the advisory noise */
58 rxi_setaddr(afs_uint32 x)
63 /* get approx to net addr */
74 /* to satisfy those who call setaddr */
76 rxi_setaddr(afs_uint32 x)
83 #if !defined(AFS_NT40_ENV)
84 /* For NT, rxi_getaddr has moved to rx_user.c. rxi_GetIfInfo is called by
85 * rx_Init which sets up the list of addresses for us.
90 /* Return our internet address as a long in network byte order. Returns zero
91 * if it can't find one.
96 afs_uint32 buffer[1024];
99 count = rx_getAllAddr(buffer, 1024);
101 return buffer[0]; /* returns the first address */
108 #if !defined(KERNEL) || defined(UKERNEL)
111 #define MAX(A,B) (((A)<(B)) ? (B) : (A))
119 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
121 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
122 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
125 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
130 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
131 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
132 if ((rtinfo->rti_addrs & (1 << i)) == 0)
134 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
141 /* this function returns the total number of interface addresses
142 ** the buffer has to be passed in by the caller
144 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
145 #if defined(AFS_OBSD42_ENV)
147 ifm_fixversion(char *buffer, size_t *size) {
148 struct if_msghdr *ifm;
152 if ((t = malloc(*size)) != NULL) {
153 memcpy(t, buffer, *size);
155 for (s = t; s < t + *size; s += ifm->ifm_msglen) {
156 ifm = (struct if_msghdr *)s;
158 if (ifm->ifm_version == RTM_VERSION) {
159 memcpy(b, ifm, ifm->ifm_msglen);
160 b += ifm->ifm_msglen;
172 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
176 struct if_msghdr *ifm, *nextifm;
177 struct ifa_msghdr *ifam;
178 struct sockaddr_dl *sdl;
179 struct rt_addrinfo info;
180 char *buf, *lim, *next;
181 int count = 0, addrcount = 0;
186 mib[3] = AF_INET; /* address family */
187 mib[4] = NET_RT_IFLIST;
189 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
191 if ((buf = malloc(needed)) == NULL)
193 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
197 #if defined(AFS_OBSD42_ENV)
198 ifm_fixversion(buf, &needed);
203 ifm = (struct if_msghdr *)next;
204 if (ifm->ifm_type != RTM_IFINFO) {
205 dpf(("out of sync parsing NET_RT_IFLIST\n"));
209 sdl = (struct sockaddr_dl *)(ifm + 1);
210 next += ifm->ifm_msglen;
214 nextifm = (struct if_msghdr *)next;
215 if (nextifm->ifm_type != RTM_NEWADDR)
218 ifam = (struct ifa_msghdr *)nextifm;
220 next += nextifm->ifm_msglen;
222 if ((ifm->ifm_flags & IFF_UP) == 0)
223 continue; /* not up */
224 while (addrcount > 0) {
225 struct sockaddr_in *a;
227 info.rti_addrs = ifam->ifam_addrs;
229 /* Expand the compacted addresses */
230 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
232 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
236 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
238 if (count >= maxSize) /* no more space */
239 dpf(("Too many interfaces..ignoring 0x%x\n",
240 a->sin_addr.s_addr));
241 else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) {
243 continue; /* skip loopback address as well. */
244 } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
246 continue; /* skip aliased loopbacks as well. */
248 buffer[count++] = a->sin_addr.s_addr;
250 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
258 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
259 afs_uint32 mtuBuffer[], int maxSize)
265 struct if_msghdr *ifm, *nextifm;
266 struct ifa_msghdr *ifam;
267 struct sockaddr_dl *sdl;
268 struct rt_addrinfo info;
269 char *buf, *lim, *next;
270 int count = 0, addrcount = 0;
275 mib[3] = AF_INET; /* address family */
276 mib[4] = NET_RT_IFLIST;
278 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
280 if ((buf = malloc(needed)) == NULL)
282 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
286 #if defined(AFS_OBSD42_ENV)
287 ifm_fixversion(buf, &needed);
289 s = socket(PF_INET, SOCK_DGRAM, 0);
295 ifm = (struct if_msghdr *)next;
296 if (ifm->ifm_type != RTM_IFINFO) {
297 dpf(("out of sync parsing NET_RT_IFLIST\n"));
301 sdl = (struct sockaddr_dl *)(ifm + 1);
302 next += ifm->ifm_msglen;
306 nextifm = (struct if_msghdr *)next;
307 if (nextifm->ifm_type != RTM_NEWADDR)
310 ifam = (struct ifa_msghdr *)nextifm;
312 next += nextifm->ifm_msglen;
314 if ((ifm->ifm_flags & IFF_UP) == 0)
315 continue; /* not up */
316 while (addrcount > 0) {
317 struct sockaddr_in *a;
319 info.rti_addrs = ifam->ifam_addrs;
321 /* Expand the compacted addresses */
322 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
324 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
328 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
330 if (a->sin_addr.s_addr != htonl(0x7f000001) ) {
331 if (count >= maxSize) { /* no more space */
332 dpf(("Too many interfaces..ignoring 0x%x\n",
333 a->sin_addr.s_addr));
337 addrBuffer[count] = a->sin_addr.s_addr;
338 a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
340 maskBuffer[count] = a->sin_addr.s_addr;
342 maskBuffer[count] = htonl(0xffffffff);
343 memset(&ifr, 0, sizeof(ifr));
344 ifr.ifr_addr.sa_family = AF_INET;
345 strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
346 if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
347 mtuBuffer[count] = htonl(1500);
349 mtuBuffer[count] = htonl(ifr.ifr_mtu);
354 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
363 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
365 return rx_getAllAddr_internal(buffer, maxSize, 0);
367 /* this function returns the total number of interface addresses
368 ** the buffer has to be passed in by the caller
370 #else /* UKERNEL indirectly, on DARWIN or XBSD */
372 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
375 int i, len, count = 0;
377 struct ifreq ifs[NIFS], *ifr;
378 struct sockaddr_in *a;
379 /* can't ever be AFS_DARWIN_ENV or AFS_XBSD_ENV, no? */
380 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
381 char *cp, *cplim, *cpnext; /* used only for AIX 41 */
384 s = socket(AF_INET, SOCK_DGRAM, 0);
387 ifc.ifc_len = sizeof(ifs);
388 ifc.ifc_buf = (caddr_t) ifs;
389 i = ioctl(s, SIOCGIFCONF, &ifc);
392 len = ifc.ifc_len / sizeof(struct ifreq);
395 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
396 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
397 ifc.ifc_len = sizeof(ifs);
398 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
400 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
401 cp += _SIZEOF_ADDR_IFREQ(*ifr)
406 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
411 for (i = 0; i < len; ++i)
414 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
415 ifr = (struct ifreq *)cp;
419 a = (struct sockaddr_in *)&ifr->ifr_addr;
421 cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
423 if (a->sin_family != AF_INET)
425 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
426 perror("SIOCGIFFLAGS");
427 continue; /* ignore this address */
429 if (a->sin_addr.s_addr != 0) {
431 if (a->sin_addr.s_addr == htonl(0x7f000001))
432 continue; /* skip loopback address as well. */
434 if (ifr->ifr_flags & IFF_LOOPBACK)
435 continue; /* skip aliased loopbacks as well. */
437 if (count >= maxSize) /* no more space */
438 dpf(("Too many interfaces..ignoring 0x%x\n",
439 a->sin_addr.s_addr));
441 buffer[count++] = a->sin_addr.s_addr;
449 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
451 return rx_getAllAddr_internal(buffer, maxSize, 0);
454 /* this function returns the total number of interface addresses
455 * the buffer has to be passed in by the caller. It also returns
456 * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
457 * gets the mask which is then passed into the kernel and is used
458 * by afsi_SetServerIPRank().
461 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
462 afs_uint32 mtuBuffer[], int maxSize)
465 #if defined(AFS_USERSPACE_IP_ADDR)
468 struct ifreq ifs[NIFS], *ifr;
469 struct sockaddr_in *a;
472 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
473 char *cp, *cplim; /* used only for AIX 41 */
476 #if !defined(AFS_USERSPACE_IP_ADDR)
477 count = rx_getAllAddr_internal(addrBuffer, 1024, 0);
478 for (i = 0; i < count; i++) {
479 maskBuffer[i] = htonl(0xffffffff);
480 mtuBuffer[i] = htonl(1500);
483 #else /* AFS_USERSPACE_IP_ADDR */
484 s = socket(AF_INET, SOCK_DGRAM, 0);
488 ifc.ifc_len = sizeof(ifs);
489 ifc.ifc_buf = (caddr_t) ifs;
490 i = ioctl(s, SIOCGIFCONF, &ifc);
495 len = ifc.ifc_len / sizeof(struct ifreq);
499 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
500 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
501 ifc.ifc_len = sizeof(ifs);
502 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
504 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
505 ifr = (struct ifreq *)cp;
507 for (i = 0; i < len; ++i) {
510 a = (struct sockaddr_in *)&ifr->ifr_addr;
511 if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
513 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
514 perror("SIOCGIFFLAGS");
515 continue; /* ignore this address */
518 if (a->sin_addr.s_addr == htonl(0x7f000001) )
519 continue; /* skip loopback address as well. */
521 if (count >= maxSize) { /* no more space */
522 dpf(("Too many interfaces..ignoring 0x%x\n",
523 a->sin_addr.s_addr));
527 addrBuffer[count] = a->sin_addr.s_addr;
529 if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
530 perror("SIOCGIFNETMASK");
531 maskBuffer[count] = htonl(0xffffffff);
533 maskBuffer[count] = (((struct sockaddr_in *)
534 (&ifr->ifr_addr))->sin_addr).s_addr;
537 mtuBuffer[count] = htonl(1500);
539 if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
540 perror("SIOCGIFMTU");
542 mtuBuffer[count] = htonl(ifr->ifr_metric);
544 #endif /* SIOCGIFMTU */
546 if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
547 perror("SIOCRIPMTU");
549 mtuBuffer[count] = htonl(ifr->ifr_metric);
551 #endif /* SIOCRIPMTU */
558 #endif /* AFS_USERSPACE_IP_ADDR */
562 #endif /* ! AFS_NT40_ENV */
563 #endif /* !KERNEL || UKERNEL */